Ric*_*rdo 25 c++ templates variadic-templates
以下程序编译成功。
template<typename T>
T sum(T x) {
return x;
}
template<typename T, typename... Args>
T sum(T x, Args... args) {
return x + sum(args...);
}
int main() {
sum(1, 2, 3, 4, 5);
}
Run Code Online (Sandbox Code Playgroud)
但是,当我切换模板函数的编写顺序时,它不再编译:
template<typename T, typename... Args>
T sum(T x, Args... args) {
return x + sum(args...);
}
template<typename T>
T sum(T x) {
return x;
}
int main() {
sum(1, 2, 3, 4, 5);
}
Run Code Online (Sandbox Code Playgroud)
我得到的编译器错误是:
错误 C2780:“T sum(T,Args...)”:需要 2 个参数 - 提供 0 个,消息:请参阅“sum”的声明
为什么会出现这种情况?这两个函数在 main() 中调用之前不是已经定义了吗?为什么它们的书写顺序很重要?
Bri*_*ian 28
您问题的核心是以下问题:当函数名称(例如sum)出现在函数模板内时,它指的是哪个函数?
你写了:
这两个函数在 main() 中调用之前不是已经定义了吗?为什么它们的书写顺序很重要?
您似乎有以下期望:当实例化函数模板并且函数名称sum出现在其中时,编译器会发现sum迄今为止已声明的所有重载。因此,根据您的理论,由于sum函数模板在调用 in 之前不会被实例化main,此时, 的两个重载sum都是可见的,因此递归调用sum应该考虑这两个重载并最终选择一元重载来终止递归。
然而,正如您所看到的,情况并非如此。如果首先声明变量sum,它最终会使用单个参数递归调用自身(忽略sum稍后声明的一元重载),然后尝试调用sum()(无参数),从而导致编译错误。
sum因此,在此示例中,当编译器看到对函数模板内部的调用时,它只会查找sum已在调用点声明的函数。当你改变顺序时,你就使得可变参数sum永远不能调用一元sum。
但实际上,事实要复杂得多。C++ 标准需要一种通俗地称为“两阶段查找”的行为。这意味着:
sum迄今为止已声明的所有名为的函数,并且sum无论它们是在封闭模板之前还是之后声明的。在您的代码中,sum仅使用类型为 的参数调用int,该类型不属于任何命名空间。因此,可变参数sum只发现自己处于第 1 阶段,而在第 2 阶段什么也没有。