繁体   English   中英

两阶段名称查找:POD与自定义类型

[英]Two-phase name lookup: PODs vs. custom types

编译和运行代码时

#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()在实例化之前被查找,这是不可能的。 任何提示?

只需在S之前定义foo(double):

#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();
}

输出:

foo(int)foo(double)

foo(int)foo(A)

编辑:所以S :: foo是一个非依赖名称,在定义模板时解析,S :: foobar是一个依赖名称,并在实例化模板时解析。

这就是为什么s1.foobar可以打印A(因为此时定义了foo(A))

由于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>::foobarTA 从定义上下文中声明foo

  • void foo(int)

    A的关联的命名空间(全局命名空间)中发现:

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

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

显然void foo(A)是最佳匹配。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM