26

考虑以下 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

我认为Koenig lookupstd::dynamic_pointer_cast会选择它,因为类型存在于命名空间中。我在这里想念什么?xstd

4

2 回答 2

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
}

—结束示例] —结束注释]

您的案例不会触发 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
}
于 2012-03-23T12:07:30.613 回答
18

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

于 2012-03-23T12:08:24.253 回答