简体   繁体   English

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

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

When compiling and running the code 编译和运行代码时

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

I get the output (using g++ 4.8, clang++ 3.2 or icpc 13.1) 我得到输出(使用g ++ 4.8,clang ++ 3.2或icpc 13.1)

foo(int)
foo(int)

foo(int)
foo(A)

While the last two lines make perfect sense to me considering the two-phase lookup rules, I would expect foo(int) foo(double) for the first two lines. 虽然考虑到两阶段查找规则,最后两行对我来说非常有意义,但我希望前两行的foo(int) foo(double)

It seems that in this case for the foobar() call foo() gets looked up before instantiation which should not be possible. 似乎在这种情况下, foobar()调用foo()在实例化之前被查找,这是不可能的。 Any hints? 任何提示?

Just define foo(double) before S : 只需在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();
}

output : 输出:

foo(int) foo(double) foo(int)foo(double)

foo(int) foo(A) 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. 编辑:所以S :: foo是一个非依赖名称,在定义模板时解析,S :: foobar是一个依赖名称,并在实例化模板时解析。

This is why s1.foobar can print A (because foo(A) is defined at this point) 这就是为什么s1.foobar可以打印A(因为此时定义了foo(A))

Since T is a template parameter, the expression t is type-dependent and hence foo is a dependent name in the function call foo(t) . 由于T是模板参数,因此表达式t依赖于类型,因此foo是函数调用foo(t)的从属名称。 [temp.dep.candidate] 14.6.4.2/1 says: [temp.dep.candidate] 14.6.4.2/1说:

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: 对于依赖于模板参数的函数调用,使用通常的查找规则(3.4.1,3.4.2,3.4.3)找到候选函数,除了:

  • 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. 对于使用非限定名称查找(3.4.1)或限定名称查找(3.4.3)的查找部分,仅找到模板定义上下文中的函数声明。

  • 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. 对于使用关联命名空间(3.4.2)的查找部分,仅找到在模板定义上下文或模板实例化上下文中找到的函数声明。

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

When instantiating S<double>::foobar , T is obviously double and has no associated namespaces. 在实例化S<double>::foobarT显然是double并且没有关联的命名空间。 So the only declarations of foo that will be found are those from the template definition context ( void foo(int) ) as described in the first bullet. 因此,将要找到的foo的唯一声明是来自模板定义上下文( void foo(int) )的声明,如第一个项目符号中所述。

When instantiating S<A>::foobar , T is A . 当实例化S<A>::foobarTA Declarations of foo from both the definition context 从定义上下文中声明foo

  • void foo(int)

    and from A 's associated namespace (the global namespace) are found: A的关联的命名空间(全局命名空间)中发现:

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

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

Clearly void foo(A) is the best match. 显然void foo(A)是最佳匹配。

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

相关问题 C ++两阶段查找成员函数的相关非限定名称 - C++ two-phase lookup for dependent unqualified name of member function 如何使重载的 function 成为从属名称,以便两阶段查找找到它? - How to make an overloaded function a dependent name, so two-phase lookup finds it? 条件运算符的返回类型和两阶段查找 - Conditional operator's return type and two-phase lookup 为什么两阶段查找无法选择'swap'的重载版本? - Why will two-phase lookup fail to choose overloaded version of 'swap'? 两阶段查找:我可以避免“代码膨胀”吗? - Two-phase lookup: can I avoid “code bloat”? 两阶段查找:可以轻松地混合继承和模板 - Two-phase lookup: is it possible to easily mix inheritence and templates 如何使Clang改变两阶段查找的规则? - How to make Clang changle the rules of two-phase lookup? 为什么我会警告C ++ / CLI,C ++ / CX或OpenMP不支持C4199两阶段名称查找;为什么? 使用/ Zc:twoPhase- - Why do I have warning C4199 two-phase name lookup is not supported for c++/cli, c++/cx, or openmp; use /Zc:twoPhase- 如何避免由共享指针所引用的带有反向引用的聚合类型的两阶段构造? - How to avoid two-phase construction of aggregated types referenced by shared pointers with back-references? 用例进行两阶段初始化 - Use cases for two-phase initialization
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM