3

编译运行代码时

#include <iostream>

struct A { A(int){} };

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

template< typename T >
struct S {
   void bar() { foo( 5 ); }
   void foobar() { T t = 5; foo(t); }
};

inline void foo( A ) { std::cout << "foo(A)" << std::endl; }
inline void foo( double ) { std::cout << "foo(double)" << std::endl; }

int main(int argc, char* argv[])
{
   S<double> s0;
   s0.bar();
   s0.foobar();

   std::cout << '\n';

   S<A> s1;
   s1.bar();
   s1.foobar();
}

我得到输出(使用 g++ 4.8、clang++ 3.2 或 icpc 13.1)

foo(int)
foo(int)

foo(int)
foo(A)

虽然考虑到两阶段查找规则,最后两行对我来说非常有意义,但我希望foo(int) foo(double)前两行。

似乎在这种情况下,foobar()调用foo()在实例化之前被查找,这是不可能的。有什么提示吗?

4

2 回答 2

5

Just define foo(double) before S :

#include <iostream>

struct A { A(int){} };

void foo( int ) { std::cout << "foo(int)" << std::endl; }
inline void foo( double ) { std::cout << "foo(double)" << std::endl; } //here
inline void foo( A ) { std::cout << "foo(A)" << std::endl; }

template< typename T >
struct S {
   void bar() { foo( 5 ); }
   void foobar() { T t = 5; foo(t); }
};

int main(int argc, char* argv[])
{
   S<double> s0;
   s0.bar();
   s0.foobar();

   std::cout << '\n';

   S<A> s1;
   s1.bar();
   s1.foobar();
}

output :

foo(int) foo(double)

foo(int) foo(A)

EDIT : So S::foo is a non-dependent name and is resolved when the template is defined and S::foobar is a dependant name and is resolved when when the template is instantiated.

This is why s1.foobar can print A (because foo(A) is defined at this point)

于 2014-05-22T14:41:10.473 回答
5

由于T是模板参数,因此表达式t是类型相关的,因此foo是函数调用中的依赖名称foo(t)。[temp.dep.candidate] 14.6.4.2/1 说:

对于依赖于模板参数的函数调用,使用通常的查找规则(3.4.1、3.4.2、3.4.3)找到候选函数,除了:

  • 对于使用非限定名称查找 (3.4.1) 或限定名称查找 (3.4.3) 的查找部分,仅找到来自模板定义上下文的函数声明。

  • 对于使用关联命名空间 (3.4.2) 的查找部分,只能找到在模板定义上下文或模板实例化上下文中找到的函数声明。

如果函数名称是非限定 ID,并且调用格式错误或找到更好的匹配,则在关联命名空间中的查找考虑所有翻译单元中的这些命名空间中引入的具有外部链接的所有函数声明,而不仅仅是考虑在模板定义和模板实例化上下文中找到的那些声明,则程序具有未定义的行为。

实例化时S<double>::foobarT显然double没有关联的命名空间。因此,唯一foo可以找到的声明是来自模板定义上下文 ( void foo(int)) 中的声明,如第一个项目符号中所述。

实例化时S<A>::foobarTAfoo来自定义上下文的声明

  • void foo(int)

    找到fromA的关联命名空间(全局命名空间):

  • inline void foo( A ) { std::cout << "foo(A)" << std::endl; }

  • inline void foo( double ) { std::cout << "foo(double)" << std::endl; }

显然void foo(A)是最好的搭配。

于 2014-05-22T17:58:22.513 回答