为什么我必须使用std :: string()来满足模板参数?

Ale*_*lke 4 c++ string templates c++11

我写了一个非常简单的模板来标记字符串,如下所示.

不过,我有调用该函数的一个问题,我不能使用的C字符串delimiterstrim_string参数.这些必须是std::string(或任何类型的字符串StringT,即std::wstring).

所以以下失败:

std::vector<std::string> tokens;
std::string str = "This string, it will be split, in 3.";
int count = tokenize_string(tokens, str, ",", true, " ");
Run Code Online (Sandbox Code Playgroud)

要解决这个问题我必须写:

std::vector<std::string> tokens;
std::string str = "This string, it will be split, in 3.";
int count = tokenize_string(tokens, str,
                       std::string(","), true, std::string(" "));
Run Code Online (Sandbox Code Playgroud)

有没有办法避免在这种情况下在标准C字符串周围使用std :: string()?

我用g ++得到的错误如下:

/home/snapwebsites/snapwebsites/snapmanagercgi/daemon/snapmanagerdaemon.cpp: In member function ‘void snap_manager::manager_daemon::init(int, char**)’:
/home/snapwebsites/snapwebsites/snapmanagercgi/daemon/snapmanagerdaemon.cpp:103:71: error: no matching function for call to ‘tokenize_string(std::vector<std::__cxx11::basic_string<char> >&, const string&, const char [2], bool, const char [2])’
         snap::tokenize_string(f_bundle_uri, bundle_uri, ",", true, " ");
                                                                       ^
In file included from /home/snapwebsites/snapwebsites/snapmanagercgi/daemon/snapmanagerdaemon.cpp:35:0:
/home/snapwebsites/BUILD/dist/include/snapwebsites/tokenize_string.h:46:8: note: candidate: template<class StringT, class ContainerT> size_t snap::tokenize_string(ContainerT&, const StringT&, const StringT&, bool, const StringT&)
 size_t tokenize_string(ContainerT & tokens
        ^
/home/snapwebsites/BUILD/dist/include/snapwebsites/tokenize_string.h:46:8: note:   template argument deduction/substitution failed:
/home/snapwebsites/snapwebsites/snapmanagercgi/daemon/snapmanagerdaemon.cpp:103:71: note:   deduced conflicting types for parameter ‘const StringT’ (‘std::__cxx11::basic_string<char>’ and ‘char [2]’)
         snap::tokenize_string(f_bundle_uri, bundle_uri, ",", true, " ");
                                                                       ^
Run Code Online (Sandbox Code Playgroud)

模板:

template < class StringT, class ContainerT >
size_t tokenize_string(ContainerT & tokens
                     , StringT const & str
                     , StringT const & delimiters
                     , bool const trim_empty = false
                     , StringT const & trim_string = StringT())
{
    for(typename StringT::size_type pos(0), last_pos(0); last_pos < str.length(); last_pos = pos + 1)
    {
        pos = str.find_first_of(delimiters, last_pos);

        // no more delimiters?
        //
        if(pos == StringT::npos)
        {
            pos = str.length();
        }

        char const * start(str.data() + last_pos);
        char const * end(start + (pos - last_pos));

        if(start != end                 // if not (already) empty
        && !trim_string.empty())        // and there are characters to trim
        {
            // find first character not in trim_string
            //
            start = std::find_if_not(
                  start
                , end
                , [&trim_string](auto const c)
                  {
                      return trim_string.find(c) != StringT::npos;
                  });

            // find last character not in trim_string
            //
            if(start < end)
            {
                reverse_cstring<typename StringT::value_type const> const rstr(start, end);
                auto p = std::find_if_not(
                      rstr.begin()
                    , rstr.end()
                    , [&trim_string](auto const c)
                      {
                          return trim_string.rfind(c) != StringT::npos;
                      });
                end = p.get();
            }
        }

        if(start != end     // if not empty
        || !trim_empty)     // or user accepts empty
        {
            tokens.push_back(typename ContainerT::value_type(start, end - start));
        }
    }

    return tokens.size();
}
Run Code Online (Sandbox Code Playgroud)

T.C*_*.C. 12

规则是,当您有三个StringT const &参数时,StringT独立于相应的参数推导出,并且推导的类型必须匹配.

您可以

  • typename ContainerT::value_type如果容器的值类型应该是正确的字符串类型,那么只需使用所有三个; 要么
  • 阻止StringT从三个StringT参数中的两个中扣除,

    • 在调用站点上,通过使用braced-init-list s 进行后两个参数的非推导上下文:

      int count = tokenize_string(tokens, str, {","}, true, {" "});
      
      Run Code Online (Sandbox Code Playgroud)
    • 或者在函数模板本身中,通过将后两个StringT参数包装到非推导的上下文中:

      template < class StringT, class ContainerT >
      size_t tokenize_string(ContainerT & tokens
                           , StringT const & str
                           , typename std::decay<StringT>::type const & delimiters
                           , bool const trim_empty = false
                           , typename std::decay<StringT>::type const & trim_string = StringT())
      
      Run Code Online (Sandbox Code Playgroud)
  • 或者为每个参数采用不同的类型参数,稍后在功能模板主体中进行协调.