c++ - 模板函数查找

标签 c++ templates

考虑这段代码:

#include <iostream>
#include <vector>

template<typename A>
void foo(A& a) {
    std::cout << "the wrong foo" << std::endl;
}

template<typename A>
void do_stuff(A& a) {
    foo(a);
}

template<typename X>
void foo(std::vector<X>& a) {
    std::cout << "the right foo" << std::endl;
}

int main()
{
    std::vector<int> q;
    do_stuff(q);
}

为什么调用“错误的”foo?如果删除了 foo 的第一个声明,则调用正确的 foo。

我正在使用 gcc 4.6.3。

更新: 如果按以下顺序声明函数,则调用正确的 foo。

template<typename A> void do_stuff(A& a) { ... }
template<typename A> void foo(A& a) { ... }
template<typename X> void foo(std::vector<X>& a) { ... }

最佳答案

观察到的行为是正确的,因为 foo(a) 是一个依赖于类型的表达式:

14.6.2.2 Type-dependent expressions                         [temp.dep.expr]

1) Except as described below, an expression is type-dependent if any
   subexpression is type-dependent.

2) this is type-dependent if the class type of the enclosing member
   function is dependent (14.6.2.1).

3) An id-expression is type-dependent if it contains

    — an identifier associated by name lookup with one or more declarations 
      declared with a dependent type,
    ...

在 14.6.4 下(从属名称解析):

14.6.4.2 Candidate functions                              [temp.dep.candidate]

For a function call that depends on a template parameter, the candidate
functions are found using the usual lookup rules (3.4.1, 3.4.2, 3.4.3) except
that:

— For the part of the lookup using unqualified name lookup (3.4.1) or qualified
  name lookup (3.4.3), only function declarations from the template definition 
  context are found.
— For the part of the lookup using associated namespaces (3.4.2), only function
  declarations found in either the template definition context or the template
  instantiation context are found.

If the function name is an unqualified-id and the call would be ill-formed or
would find a better match had the lookup within the associated namespaces
considered all the function declarations with external linkage introduced in
those namespaces in all translation units, not just considering those
declarations found in the template definition and template instantiation
contexts, then the program has undefined behavior.

“错误的”foo() 被选中是因为它是唯一可见的模板定义点,而“正确的”foo() 不被考虑,因为它不在与函数参数类型关联的命名空间中

如果您修改您的代码,使“正确的”foo() 位于关联的命名空间中,它将被选中而不是“错误的”foo()。 (在这种特殊情况下,标准不允许这样做,所以不要执行以下操作,但是对于您自己的命名空间/类型,这应该是这样工作的)

#include <iostream>
#include <vector>

template<typename A> void foo(A& a)
{
    std::cout << "the wrong foo" << std::endl;
}

template<typename A>
void do_stuff(A& a) {
    foo(a);
}

namespace std { // evil, don't do this with namespace std!

template<typename X>
void foo(std::vector<X>& a) {
    std::cout << "the right foo" << std::endl;
}

}

int main()
{
    std::vector<int> q;
    do_stuff(q); // calls the "right" foo()
}

关于c++ - 模板函数查找,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12530174/

相关文章:

c++ - 使用基类指针作为方法的参数

c++ - 在 OpenGL C++ 中同时使用 glOrtho 和 gluPerspective

python - 如何在调用 render() 时获取 Django 模板错误的文件名和行号?

c++ - 一个好的 C++ 编译器会优化引用吗?

c++ - 根据模板参数命名成员函数

c++ - 在 C++ 中产生 typename 和 typedef 相关错误的模板类?

c++ - 消除 HTML 的最佳 C/C++ 库?

c++ - 必须重新定义一些 kext 成员函数,以避免未解析的符号

c++ - 成员函数与非成员函数?

c++ - 如何用模板解决这个循环继承问题?