2
votes

I have two functions that split a string and add tokens into vector:

template < typename InputIterator, typename ContainerType >
void Slice(InputIterator begin,
           InputIterator end,
           typename InputIterator::value_type delimiter,
           ContainerType& container)
{
    using CharType = InputIterator::value_type;
    InputIterator right = begin;
    while (true) {
      begin = find_if_not(right, end, [ delimiter ](CharType c) { return c == delimiter; });
      if (begin == end) {
        break;
      } else {
        right = find_if(begin + 1, end, [ delimiter ](CharType c) { return c == delimiter; });
        container.push_back(std::basic_string< CharType >(begin, right));
      }
    }
}

template < typename InputIterator, typename ContainerType >
void Slice(InputIterator begin,
           InputIterator end,
           InputIterator delimitersBegin,
           InputIterator delimitersEnd,
           ContainerType& container)
{...}

It works well in calls like

std::string headers;
std::vector<std::string> rawHeaders;
Slice(headers.begin(), headers.end(), '\0', rawHeaders)

and doesn't work for const char*:

auto begin = headers.c_str();
auto end = begin + headers.size();
Slice(begin, end, '\0', rawHeaders);

Errors are (I use MSVC2017 with MSVC2013 toolchain):

error C2780: 'void Slice(InputIterator,InputIterator,InputIterator,InputIterator,ContainerType &)' : expects 5 arguments - 4 provided

error C2893: Failed to specialize function template 'void Slice(InputIterator,InputIterator,InputIterator::value_type,ContainerType &) With the following template arguments: 'InputIterator=const char *' 'ContainerType=std::vectorstd::string,std::allocator<_Ty>'

Update: added function body. And currently it's preferred not to use additional features like std::span. I was hoping for the following string constructor:

template< class InputIt >
basic_string( InputIt first, InputIt last, const Allocator& alloc = Allocator() );

Update 2: Still doesn't work but for different reason, I tried to change delimiter type:

 template < typename InputIterator, typename ContainerType >
  void Slice(
      InputIterator begin,
      InputIterator end,
      typename std::iterator_traits< InputIterator >::value_type delimiter,
      //typename InputIterator::value_type delimiter,
      ContainerType& container)
  {
    using CharType = typename std::iterator_traits< InputIterator >::value_type;

Now it says:

error C3861: 'find_if_not': identifier not found. see reference to function template instantiation 'void StringUtils::Slice<char*,std::vectorstd::string,std::allocator<_Ty>>(InputIterator,InputIterator,char,ContainerType &)' being compiled with [_Ty=std::string, InputIterator=char *, ContainerType=std::vectorstd::string,std::allocator<std::string>

And also:

error C3861: 'find_if': identifier not found

2
Raw pointers are iterators. The issue looks to be with that the functions expects a container to be passed at the end. You are passing in raw pointers and a std::vector<std::string> which clearly don't match.super
@super functions expects a container ... You are passing in raw pointers and a std::vector<std::string> which clearly don't match. I don't get your point. Is vector not a container? Why doesn't it match?eerorika
@eerorika Ah, right. My bad.super

2 Answers

7
votes

SFINAE kicks in. The signature

template < typename InputIterator, typename ContainerType >
void Slice(InputIterator begin,
           InputIterator end,
           typename InputIterator::value_type delimiter,
           ContainerType& container)

is not a possible candidate because there is no nested member ::value_type in a const char*.

You probably want this signature instead:

template < typename InputIterator, typename ContainerType >
void Slice(InputIterator begin,
           InputIterator end,
           typename std::iterator_traits<InputIterator>::value_type delimiter,
           ContainerType& container)
0
votes

You could use a std::span.

Wrap it around your pointers. It's lightweight and fast. I'm not sure if it's already in your toolchain.