Подтвердить что ты не робот

Почему зависящий от аргумента поиск не работает с шаблоном функции dynamic_pointer_cast

Рассмотрим следующую программу на С++:

#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 будет выбрано поиск Koenig, так как тип x находится в пространстве имен std. Что мне здесь не хватает?

4b9b3361

Ответ 1

Я думаю, что раздел §14.8.1/6 (С++ 03, и я думаю, что он содержится в С++ 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
}

Ответ 2

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