Почему Argument Dependent Lookup не работает с шаблоном функции dynamic_pointer_cast - PullRequest
26 голосов
/ 23 марта 2012

Рассмотрим следующую программу на 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. Что мне здесь не хватает?

Ответы [ 2 ]

24 голосов
/ 23 марта 2012

Я думаю, что раздел §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
}
18 голосов
/ 23 марта 2012

Поиск Кенига относится только к поиску функций.Здесь вам сначала нужно найти шаблон, а затем создать его экземпляр, прежде чем вы получите функцию.Чтобы просто разобрать код, компилятор должен знать, что dynamic_pointer_cast является шаблоном (в противном случае '<' меньше, чем начало списка аргументов шаблона);пока компилятор не узнает, что <code>dynamic_pointer_cast является шаблоном функции, он даже не знает, что вызов функции задействован.Выражение, которое он видит, в основном a < b > c, где < и > - операторы отношений.

...