这是我第一次使用模板,所以我怀疑我使用不正确。
在我的代码中,我多次从控制台获得每行的空格分隔值列表。有时我希望列表是一对std::strings
或一个std::string
和一个int
- 您明白了。所以我想创建一个类型模糊的函数,只需引用列表即可立即处理所有函数。
以下工作正常:
template<typename A, typename B> void getInputList(std::vector<std::pair<A, B>> &list) {
//redacted while loop
A a;
B b;
if ((ss >> a >> b) && ss.eof())
list.push_back(std::make_pair(a, b));
else {
std::cout << "Bad values ignored" << ((list.size() != 0) ? ", previous values still in buffer.\n" : ".\n");
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
但是,如果类型为std::string
和int
,我输入:
56 56
代码会接受它,我希望字符串只是alphas。那么我添加了一个测试,看看其中一个输入是std::string
,如果是,请确保它没有数字:
template<typename A, typename B> void getInputList(std::vector<std::pair<A, B>> &list) {
//redacted while loop
A a;
B b;
if ((ss >> a >> b) && ss.eof()) {
if (std::is_same<A, std::string>::value)
if(std::all_of(a.begin(), a.end(), ::isdigit))
continue;
if (std::is_same<B, std::string>::value)
if(std::all_of(b.begin(), b.end(), ::isdigit))
continue;
list.push_back(std::make_pair(a, b));
continue;
}
//more redacted code
}
这会产生以下错误,但b
仅 ,a
不会引发任何错误:
'.begin'左边的必须有class / struct / union
'。end'的左边必须有class / struct / union
我创建了一个临时函数来查看原因,而a
的类型为A
,b
的类型为int
。
bool isString(std::string in) {
return std::all_of(in.begin(), in.end(), ::isdigit);
}
template<typename A, typename B> void getInputList(std::vector<std::pair<A, B>> &list) {
//redacted while loop
A a;
B b;
if ((ss >> a >> b) && ss.eof()) {
if (std::is_same<A, std::string>::value)
if(isString(a))
continue;
if (std::is_same<B, std::string>::value)
if(isString(b))
continue;
list.push_back(std::make_pair(a, b));
continue;
}
//more redacted code
}
给出了:
无法从'int'转换为'std :: string'
如果我同时应用std::to_string
,则a
会产生错误:
'std :: to_string':9个重载中没有一个可以转换所有参数类型
因为它应该是A
类型......
我做错了什么?
答案 0 :(得分:2)
在大多数情况下,函数模板特化中的所有语句必须有效,即使它们永远不会被执行。
如果您可以使用C ++ 17,它会引入&#34; if constexpr
&#34;解决此问题:当您键入if constexpr
而不是if
时,必须可以在编译时评估条件,并且可能无法对给定的模板参数集执行任何受控语句没有用这些模板参数进行实例化。
如果您不能使用C ++ 17,您可以派遣帮助函数进行验证。关键是根据类型是std::string
还是其他东西来调用不同的函数。
// A string must not be all digits:
inline bool validateInput(const std::string& s) {
return !std::all_of(s.begin(), s.end(), ::isdigit);
}
// Any other type is always valid:
template <typename T>
bool validateInput(const T&) { return true; }
template<typename A, typename B>
void getInputList(std::vector<std::pair<A, B>> &list) {
// ...
while (something()) {
A a;
B b;
if ((ss >> a >> b) && ss.eof()) {
if (!validateInput(a)) continue;
if (!validateInput(b)) continue;
list.push_back(std::make_pair(a, b));
continue;
}
// ...
}
}
答案 1 :(得分:1)
问题是您的类型检查(std::is_same<A, std::string>::value
)是运行时测试。
所以编译器不知道它是否真实,然后继续。
然后使用模板化类型变量调用带有std::string
参数的函数。当您的模板为int
(或其他任何内容)时,这会导致类型错误。
要解决此问题,我建议您使用模板专业化:
// base template, used if no specialization matches
template<typename T>
bool stringContainingDigits(T in) {
// no string
return false;
}
// string specialization only used if string
template<>
bool stringContainingDigits<std::string>(std::string in) {
// true if only contains digits
return std::all_of(in.begin(), in.end(), ::isdigit);
}
template<typename A, typename B>
void getInputList(std::vector<std::pair<A, B>> &list) {
//redacted while loop
A a;
B b;
if ((ss >> a >> b) /* && ss.eof() */) {
if(stringContainingDigits(a))
continue;
if(stringContainingDigits(b))
continue;
list.push_back(std::make_pair(a, b));
continue
}
//more redacted code
}
顺便说一句,如果你在一个循环中有if
语句,继续从同一个流ss
读取,你可能宁愿省略EOF测试,因为它只适用于最后一个项目