Почему Argument Dependent Lookup не работает с шаблоном функции dynamic_pointer_cast

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

Решение

Я думаю, что раздел §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
}

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

Другие вопросы по тегам