我正在尝试学习c ++模板。脚本中的一个函数会编译,而看似相似的函数会失败。整个脚本是:
#include <string>
#include <vector>
using std::vector;
template <typename T>
void works(vector<int>& vi, vector<double>& vd, vector<T>& inp) {
if (std::is_same<T, double>::value)
vd.push_back(inp[0]);
else if (std::is_same<T, int>::value)
vi.push_back(inp[0]);
}
template <typename T>
void doesnt_work(vector<std::string>& vs, vector<double>& vd, vector<T>& inp) {
if (std::is_same<T, double>::value)
vd.push_back(inp[0]);
else if (std::is_same<T, std::string>::value)
vs.push_back(inp[0]); // Line 18: no matching member function
}
int main() {
vector<double> d = {2, 3, 4};
vector<double> doubles;
vector<std::string> strings;
vector<int> ints;
doesnt_work(strings, doubles, d); // Line 26: Comment out and script runs
works(ints, doubles, d);
return 0;
}
函数works
将包含vi
和vd
的两个向量int
和double
以及带有元素类型的第三个向量作为引用T.然后,我尝试检查T
的类型,并将向量inp
的第一个元素放入vi
或vd
中。相反,函数doesnt_work
会引起问题。代替接受int
的向量作为参数,它接受std::string
的向量。在第26行注释时,我可以运行整个脚本。否则,clang++
告诉我
error: no matching member function for call to 'push_back'
vs.push_back(inp[0]);
有人请问我在做什么错吗?我不明白为什么程序无法访问向量push_back
的函数vs
。
答案 0 :(得分:3)
template <typename T>
void now_works(vector<std::string>& vs, vector<double>& vd, vector<T>& inp) {
if constexpr (std::is_same<T, double>::value)
vd.push_back(inp[0]);
else if constexpr (std::is_same<T, std::string>::value)
vs.push_back(inp[0]); // Line 18: no error
}
您的问题是所有分支即使未运行也都已编译。
if constexpr
对其进行编译,然后在编译时将其丢弃,而忽略任何类型错误。
代码有效,即使不运行,一切都可以转换,因此可以编译。
无效的代码,要排除的转换是非法的,因此在编译时失败。
请注意,if constexpr
仅起作用是因为branching子句是一个编译时常量,并且因为它在模板中,并且该子句取决于模板参数,并且无效的代码也取决于在模板参数上。
如果您还没有if constexpr
,因为您被困在旧版本的C ++上,那么您将被迫做一些丑陋的事情,例如带有帮助功能的标签分发或SFINAE或其他更神秘的事情。