考虑以下C ++程序:
#include <memory>
struct A {};
struct B : A {};
int main()
{
auto x = std::make_shared<A>();
if (auto p = dynamic_pointer_cast<B>(x));
}
使用MSVC 2010进行编译时,我收到以下错误:
error C2065: 'dynamic_pointer_cast' : undeclared identifier
如果auto
替换为std::shared_ptr<A>
,则错误仍然存在。当我使用std::dynamic_pointer_cast
完全限定呼叫时,程序会成功编译。
此外,gcc 4.5.1也不喜欢它:
error: 'dynamic_pointer_cast' was not declared in this scope
我认为std::dynamic_pointer_cast
会选择x
,因为std
的类型位于{{1}}命名空间中。我在这里缺少什么?
答案 0 :(得分: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 }
-end example] -end note]
您的案例不会触发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
}
答案 1 :(得分:18)
Koenig查找仅适用于查找函数。在这里,首先必须找到一个模板,然后在有函数之前对其进行实例化。为了简单地解析代码,编译器必须知道dynamic_pointer_cast
是一个模板(否则,'&lt;'小于,而不是模板参数列表的开头);直到编译器知道dynamic_pointer_cast
是一个函数模板,它甚至不知道涉及函数调用。它看到的表达式基本上是a < b > c
,其中<
和>
是关系运算符。