模板函数中的std :: string的类型推断失败

时间:2019-05-15 13:56:02

标签: c++ string templates vector

我正在尝试学习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将包含vivd的两个向量intdouble以及带有元素类型的第三个向量作为引用T.然后,我尝试检查T的类型,并将向量inp的第一个元素放入vivd中。相反,函数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

1 个答案:

答案 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或其他更神秘的事情。