为什么Argument Dependent Lookup不能与函数模板dynamic_pointer_cast一起使用

Ale*_* C. 26 c++ argument-dependent-lookup

考虑以下C++程序:

#include <memory>

struct A {};

struct B : A {};

int main()
{
    auto x = std::make_shared<A>();
    if (auto p = dynamic_pointer_cast<B>(x));
}
Run Code Online (Sandbox Code Playgroud)

使用MSVC 2010进行编译时,我收到以下错误:

error C2065: 'dynamic_pointer_cast' : undeclared identifier
Run Code Online (Sandbox Code Playgroud)

如果auto被替换,则错误仍然存​​在std::shared_ptr<A>.当我完全符合要求时std::dynamic_pointer_cast,程序会成功编译.

另外,gcc 4.5.1也不喜欢它:

error: 'dynamic_pointer_cast' was not declared in this scope
Run Code Online (Sandbox Code Playgroud)

我认为Koenig查找std::dynamic_pointer_cast会选择它,因为命名空间中的生命类型.我在这里错过了什么?xstd

Naw*_*waz 24

我认为第14.8.1/6节(C++ 03,我认为它也适用于C++ 11)适用于这种情况,如下所示:

[注意:对于简单的函数名称,即使函数名称在调用范围内不可见,依赖于参数的查找(3.4.2)也适用.这是因为调用仍然具有函数调用的语法形式(3.4.1).但是当使用具有显式模板参数的函数模板时,除非在调用点处有一个具有该名称的函数模板,否则调用没有正确的语法形式.如果看不到这样的名称,则调用语法不完善,并且参数依赖查找不适用.如果某些此类名称可见,则应用依赖于参数的查找,并且可以在其他名称空间中找到其他函数模板.

[例:

namespace A {
     struct B { };
     template<int X> void f(B);
}
namespace C {
     template<class T> void f(T t);
}
void g(A::B b) {
     f<3>(b);    //ill-formed: not a function call
     A::f<3>(b); //well-formed
     C::f<3>(b); //ill-formed; argument dependent lookup
                 // applies only to unqualified names

    using C::f;
     f<3>(b); //well-formed because C::f is visible; then
              // A::f is found by argument dependent lookup
}
Run Code Online (Sandbox Code Playgroud)

- 末端示例] - 尾注]

您的情况不会触发ADL,因为您显式传递了模板参数,并且您调用的站点上没有可用的相同名称的模板dynamic_pointer_cast.

启用ADL的一个技巧是在代码中添加一个具有相同名称的虚拟模板,如下所示:

#include <memory>

struct A {};

struct B : A {};

template<int> //template parameter could be anything!
void dynamic_pointer_cast(); //ADD this. NO NEED TO DEFINE IT

int main()
{
   auto x = std::make_shared<A>();
   if (auto p = dynamic_pointer_cast<B>(x)); //now it should work through ADL
}
Run Code Online (Sandbox Code Playgroud)


Jam*_*nze 18

Koenig查找仅适用于查找函数.在这里,首先必须找到一个模板,然后在有函数之前对其进行实例化.为了简单地解析代码,编译器必须知道它dynamic_pointer_cast是一个模板(否则,'<'小于,而不是模板参数列表的开头); 直到编译器知道它dynamic_pointer_cast是一个函数模板,它甚至不知道涉及函数调用.它看到表达基本上是a < b > c,在这里<>是关系运算符.

  • @Nawaz最后,它不起作用,因为标准说它没有,并且有几个原因,为什么标准不说让它工作.你给出的那个和我解释的那个(来自委员会的讨论,很多年前)都回到了同样的基本问题:为了正确地解析表达式,编译器必须知道符号是一个模板,并且为了知道它,它必须查找它.并且它不能使用Koenig查找查找它,因为它还没有足够的解析来知道有一个函数调用. (5认同)