我有一个C++
函数,它使用逗号分隔的字符串并在std::vector<std::string>
中拆分:
std::vector<std::string> split(const std::string& s, const std::string& delim, const bool keep_empty = true) {
std::vector<std::string> result;
if (delim.empty()) {
result.push_back(s);
return result;
}
std::string::const_iterator substart = s.begin(), subend;
while (true) {
subend = std::search(substart, s.end(), delim.begin(), delim.end());
std::string temp(substart, subend);
if (keep_empty || !temp.empty()) {
result.push_back(temp);
}
if (subend == s.end()) {
break;
}
substart = subend + delim.size();
}
return result;
}
但是,我真的希望能够将此函数应用于多种数据类型。例如,如果我有输入std::string
:
1,2,3,4,5,6
然后我希望函数的输出是int
s的向量。我对C++
还不熟悉,但我知道有一些名为template
的类型,对吗?是否可以将此功能创建为通用模板?或者我误解了template
函数的工作原理?
答案 0 :(得分:4)
您可以将模板函数声明为:
template<class ReturnType>
std::vector<ReturnType> split(const std::string&, const std::string&, const bool = true);
然后针对您想要允许的每种矢量类型进行专门化:
template<>
std::vector<std::string> split(const std::string& s, const std::string& delim, const bool keep_empty) {
// normal string vector implementation
}
template<>
std::vector<int> split(const std::string& s, const std::string& delim, const bool keep_empty) {
// code for converting string to int
}
// ...
您可以阅读有关字符串到整数转换的here。
然后,您需要将split
称为:
auto vec = split<int>("1,2,3,4", ",");
答案 1 :(得分:4)
你可以“模板化”这个功能 - 启动它你只需要在函数前用'std :: vector std::vector<std::string>
template替换and add
。但是你需要注意如何将字符串放入结果向量中。在您当前的实现中,您只需
result.push_back(temp);
因为result
是字符串的向量,而temp是字符串。在一般情况下虽然不可能,并且如果你想使用这个功能,例如vector<int>
此行不会编译。但是,使用另一个函数 - 模板可以轻松解决此问题 - 它会将字符串转换为您要使用的任何类型split
。我们称这个函数为convert
:
template<typename T> T convert(const std::string& s);
然后,您需要为您需要的任何类型提供此功能的特化。例如:
template<> std::string convert(const std::string& s) { return s; }
template<> int convert(const std::string& s) { return std::stoi(s); }
通过这种方式,您不需要像其他答案所示那样专门化整个功能,只需要根据类型来确定部分。对于行
也应该这样做result.push_back(s);
在没有分隔符的情况下。
答案 2 :(得分:3)
使用Boost.LexicalCast可以非常轻松地推广您的函数以返回任意类型的vector
。唯一的打嗝是这种情况:
if (delim.empty()) {
result.push_back(s);
return result;
}
这仅适用于输入和输出类型std::string
,但如果您返回的vector
包含std::string
以外的类型,则显然无效。使用boost::lexical_cast
执行此类无效转换将导致boost::bad_lexical_cast
被抛出。所以也许你想重新考虑那个部分,但是否则实现很简单。
#include <boost/lexical_cast.hpp>
template<typename Result>
std::vector<Result>
split(const std::string& s, const std::string& delim, const bool keep_empty = true)
{
std::vector<Result> result;
if (delim.empty()) {
result.push_back(boost::lexical_cast<Result>(s));
return result;
}
std::string::const_iterator substart = s.begin(), subend;
while (true) {
subend = std::search(substart, s.end(), delim.begin(), delim.end());
std::string temp(substart, subend);
if (keep_empty || !temp.empty()) {
result.push_back(boost::lexical_cast<Result>(temp));
}
if (subend == s.end()) {
break;
}
substart = subend + delim.size();
}
return result;
}
基本上,我所做的就是将结果类型作为模板参数并替换为
result.push_back(x);
与
result.push_back(boost::lexical_cast<Result>(x));
如果您无法使用Boost,请查看this answer,了解如何使用stringstream
将字符串转换为其他类型。