2016-03-15 61 views
3

我有一个方便的功能,将字符串拆分为多个部分。实施对我的问题并不重要。使用模板和字符串?

inline std::vector<std::string> & split(const std::string & strInput, const std::string & strPattern, std::vector<std::string> & vec_strPart) 
    {...} 

我想使这个功能的模板化版本,以支持wstrings和其他类型的字符串。但是,如果我这样做

template <class StringType> 
inline std::vector<StringType> & tsplit(const StringType & strInput, const StringType & strPattern, std::vector<StringType> & vec_strPart) 
    {...} 

那么它不能如预期般

const std::string str("bla bla blaaaa"); 
const std::string strPattern(" "); 
std::vector<std::string> vec_strPart; 

split(str, strPattern, vec_strPart); // works 
tsplit(str, strPattern, vec_strPart); // works 
split(str, " ", vec_strPart); // works 
tsplit(str, " ", vec_strPart); // does not work, StringType is ambiguous 
tsplit(str, std::string(" "), vec_strPart); // works but changes client's code 

我的问题是,为什么使用字符串常量,而它与untemplated一个工作不与模板版本携手。我的假设是,在未模糊的情况下,存在从char[]std::string的隐式转换,而对于模板,匹配发生在隐式转换之前。

我该如何弥补“模糊性问题”?我是否可以制作tsplit的专用版本,该版本的转换为std::string,并调用tsplit

+0

也许你可以检查拆分方法中变量的类型(如果不允许修改客户端代码)。看看:http://en.cppreference.com/w/cpp/language/typeid – asalic

回答

3

std::stringconst char*是不同的类型,所以在

tsplit(str, " ", vec_strPart); 

,如果你想它是暧昧StringTypestd::stringconst char*。要解决这个问题

一种方法是有模板为每一个参数:

template <typename String, typename InputString, typename PatternString> 
std::vector<String>& tsplit(const InputString & input, 
          const PatternString& pattern, 
          std::vector<String>& res); 

的另一种方式是只推导出一个参数,并提出一些论点非抵扣:

// Helper 
template <typename T> struct non_deducible { using type = t; }; 
template <typename T> using non_deducible_t = typename non_deducible<T>::type; 

template <typename String> 
std::vector<String>& tsplit(const non_deducible_t<String>& input, 
          const non_deducible_t<String>& pattern, 
          std::vector<String>& res); 
+0

这是C++ 03还是C++ 11? – Fabian

+0

可以在C++ 03来完成,通过'的typedef吨型取代'使用类型= t';',并删除'non_deducible_t'的定义和由'类型名称non_deducible :: type'取代'non_deducible_t '。 – Jarod42

+1

尼斯招用非抵扣。实际回答OP的问题也是+1。 –

2

如果你声明这样

template <class StringType, class TextTypeA, class TextTypeB> 
inline std::vector<StringType> & tsplit(TextTypeA strInput, TextTypeB strPattern, std::vector<StringType> & vec_strPart) 
{ 
... 
} 

你的函数,那么你的榜样编译。自动转换然后推迟到您的实施。

所以执行的事项;-)

+0

然后我需要在实施的开始时明确转换吗?像这样'const StringType strInputInternal(strInput); const StringType strPatternInternal(strPattern);'另一个问题:你有一个特殊的原因使用值调用,而不是通过调用? – Fabian

+0

显式转换可能是一个简单的解决方案,但也可以使用其他选项。转换可以自动沿着线路进行。例如,如果您使用find_if明确地使用StringType来避免歧义。 – marom

+0

关于通过电话值一个const裁判可能是更好的,你是对的。但必须经过测试。 – marom

0
template < 
    typename StringType, 
    typename PatternStringType, 
    typename ResultsStringType> 

inline std::vector<ResultsStringType>& tsplit(
    const StringType& strInput, 
    const PatternStringType& strPattern, 
    std::vector<ResultsStringType>& vec_strPart) 
{ 
    return vec_strPart; // your implementation 
} 

出的话题:为什么返回值,如果你给第三个参数,做你真正需要的结果字符串类型模板参数?也许最好能够具备以下条件之一:

template <typename StringType, typename PatternStringType> 
inline std::vector<StringType> tsplit(const StringType& strInput, const PatternStringType& strPattern) 
{ 
    return std::vector<StringType>(); // your implementation 
} 

template <typename StringType, typename PatternStringType> 
inline void tsplit(const StringType& strInput, const PatternStringType& strPattern, std::vector<StringType>& resultingStrs) 
{ 
    // your implementation 
}