2012-06-06 32 views
1

我试图创建一个字符串分割模板,如下所示,我得到错误。错误C2893:无法专门化函数模板C++

struct splitX 
{ 
    enum empties_t { empties_ok, no_empties }; 
}; 

template <typename Container> 
Container& split(
    Container&         result, 
    const typename Container::value_type&  s, 
    typename Container::value_type::value_type delimiter, 
    splitX::empties_t       empties = splitX::empties_ok) 
{ 
    result.clear(); 
    std::istringstream ss(s); 
    while (!ss.eof()) 
    { 
     typename Container::value_type field; 
     getline(ss, field, delimiter); 
     if ((empties == split::no_empties) && field.empty()) continue; 
     result.push_back(field); 
    } 
    return result; 
} 

这种失败,从标题的错误,当我试图用向量类象下面这样使用它:

std::getline(myfile,line); 
std::vector<std::string> fields; 
split(fields,line,' '); 

// Test split function 
std::cout << line << std::endl; 
for(int i = 0; i < fields.size();i++) 
    std::cout << fields[i]; 

回答

3

好吧,Microsoft Visual C++ 2008不喜欢你的Container::value_type::value_type

你可以使用这个可怕的建设:

template <typename T> 
struct vte /*value_type_extractor*/ 
{ 
    typedef typename T::value_type type; 
}; 

template <typename Container> 
Container& split(
    Container&         result, 
    const typename Container::value_type&  s, 
    typename vte<typename vte<Container>::type>::type delimiter, 
    splitX::empties_t       empties = splitX::empties_ok) 
{ 
    typedef typename Container::value_type string_type; 
    typedef typename string_type::value_type elem_type; 
    std::basic_istringstream<elem_type> ss(s); 
    ... 
} 

或者,你可以做到这一点的STL风格:

#inlcude <iterator> 

template <typename OutputIterator, typename StringType> 
OutputIterator split(
    OutputIterator     out, 
    const StringType&    s, 
    typename StringType::value_type delimiter, 
    splitX::empties_t    empties = splitX::empties_ok) 
{ 
    typedef typename StringType::value_type elem_type; 
    std::basic_istringstream<elem_type> ss(s); 
    while (!ss.eof()) 
    { 
     StringType field; 
     std::getline(ss, field, delimiter); 
     if ((empties == splitX::no_empties) && field.empty()) continue; 
     *out++ = field; 
    } 
    return out; 
} 

//somewhere in code 
{ 
    ... 
    split(std::back_inserter(your_container), line, ' '); 
} 

或者,你可以停止假装是一个模板神,写两个重载功能:

template <typename Container> 
Container& split(
    Container&    result, 
    const std::string&  s, 
    char     delimiter, 
    splitX::empties_t  empties = splitX::empties_ok) 
{ 
    std::istringstream ss(s); 
    ... 
} 

template <typename Container> 
Container& split(
    Container&    result, 
    const std::wstring&  s, 
    wchar_t     delimiter, 
    splitX::empties_t  empties = splitX::empties_ok) 
{ 
    std::wistringstream ss(s); 
    ... 
} 
+0

不要忘了错别字! – Forgottn

+0

这不是假装成为模板神,我想。如果一种编程语言在这种情况下可以有用(避免代码重复),为什么不使用它? –

+0

然后你可以使用第一个代码示例。请参阅我已添加的一些修补程序。 – Forgottn

2

目视检查你的代码,我真的没有出什么不对劲。我做了一个剪切和粘贴你的程序,在你的测试代码周围放一个main并编译它(FC 15上的库存g ++)。

编译器在您的split函数中发现错字。 split::no_empties应该是splitX::no_empties。另外,在启用警告的情况下,它报告for循环将签名类型与无符号类型进行比较。

修复该错字,并编译器警告后,例程编译和运行良好。

+2

请评论一下投票,所以我知道该怎么改进。谢谢! – jxh

+0

不幸的是,这不是一个真正的答案,但这看起来更好。请指定您的编译器。 – Forgottn