Почему 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
, где <
а также >
являются реляционными операторами.