调用模板函数时出现意外输出

时间:2018-04-04 05:03:37

标签: c++ templates gcc

以下代码是我正在经历的cpp测验的一部分:

#include <iostream>

template<typename T>
void foo(T)
{
    std::cout << "T" << std::endl;;
}

struct S
{
};

template<typename T>
void call_foo(T t)
{
    foo(S());
    foo(t);
}

void foo(S)
{
    std::cout << "S" << std::endl;
}

int main()
{
    call_foo(S());
}

我无法理解为什么输出结果为TS。我预计它会SS

  

编译器:gcc版本4.8.5 20150623

2 个答案:

答案 0 :(得分:4)

  

§14.6¶9陈述:“当寻找a中使用的名称的声明时   模板定义,使用通常的查找规则(§3.4.1,§3.4.2)   对于非依赖名称。查找依赖于模板的名称   参数被推迟,直到知道实际模板参数   (§14.6.2)。“

对foo的第一次调用是非依赖调用,因此在定义函数模板时会查找它。在第二次调用的情况下,它被推迟到模板被实例化,因为它取决于模板参数。

template<typename T> void call_foo_function(T t)
{
    foo(S()); // Independent, looks up foo now.
    foo(t); // Dependent, looks up foo later.
}

在定义函数模板时查找foo时,唯一存在的foo版本是模板化的foo(T)。具体来说,foo(S)尚不存在,也不是候选者。

有趣的是检查你的代码在Visual Studio中输出的内容,我认为在这种情况下它会输出你期望的SS

答案来源:CPPQuiz

不幸的是,由于我无法再找到答案,因此我没有答案的确切链接。

答案 1 :(得分:3)

您期望通过参数依赖查找以相同方式解析两个调用。但在这种情况下:

foo(S());
foo(t);

第一个foo不是从属名称。回想一下,模板中函数的名称查找有两种方式:

  • 在功能模板的定义点处对所有重载进行定期非限定名称查找。
  • 对于依赖名称,依赖于参数的查找在模板定义和实例化时都完成。

因为第一次调用不依赖,所以只进行常规的非限定名称查找。此时,唯一可见的重载是您之前定义的函数模板foo。第二个重载尚未可用,因此未调用。