Получение элемента из кортежа
Возможный дубликат:
Почему ADL не находит шаблоны функций?
Вызов get
, похоже, не вызывает зависимый от аргумента поиск:
auto t = std::make_tuple(false, false, true);
bool a = get<0>(t); // error
bool b = std::get<0>(t); // okay
g++ 4.6.0 говорит:
error: 'get' was not declared in this scope
Visual Studio 2010 говорит:
error C2065: 'get': undeclared identifier
Почему?
Ответы
Ответ 1
Это потому, что вы пытаетесь явно создать экземпляр шаблона функции get
, предоставив 0
в качестве аргумента шаблона. В случае шаблонов ADL работает, если шаблон функции с этим именем отображается в точке вызова. Этот видимый шаблон функции помогает только запускать ADL (он может не использоваться на самом деле), а затем наилучшее совпадение может быть найдено в других пространствах имен.
Обратите внимание, что шаблон функции, который запускает (или разрешает) ADL, не должен иметь определение:
namespace M
{
struct S{};
template<int N, typename T>
void get(T) {}
}
namespace N
{
template<typename T>
void get(T); //no need to provide definition
// as far as enabling ADL is concerned!
}
void f(M::S s)
{
get<0>(s); //doesn't work - name `get` is not visible here
}
void g(M::S s)
{
using N::get; //enable ADL
get<0>(s); //calls M::get
}
В g()
имя N::get
вызывает ADL при вызове get<0>(s)
.
Демо: http://ideone.com/83WOW
С++ (2003) раздел §14.8.1/6 гласит,
[Примечание. Для имен простых функций зависимый от аргументов поиск (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]
Ответ 2
ADL напрямую не применяется к идентификатору шаблона, например get<0>
, поэтому компилятор действительно не запускается по этому пути. С++ 11 §14.8.1/8 (в С++ 03, 14.8.1/6):
[Примечание. Для имен простых функций зависимый от аргументов поиск (3.4.2) применяется даже тогда, когда имя функции не отображается в пределах области вызова. Это связано с тем, что вызов по-прежнему имеет синтаксическую форму вызова функции (3.4.1). Но когда используется шаблон функции с явными аргументами шаблона, вызов не имеет правильной синтаксической формы, если нет шаблона функции с таким именем, видимым в точке вызова. Если такое имя не отображается, вызов не является синтаксически корректным, а зависящий от аргумента поиск не применяется. Если какое-то такое имя видимо, применяется зависимый от аргумента поиск, а дополнительные шаблоны функций могут быть найдены в других пространствах имен.
Далее приводится краткий пример. Поэтому обходной путь довольно прост:
#include <tuple>
template< typename > // BEGIN STUPID BUT HARMLESS HACK
void get( struct not_used_for_anything ); // END STUPIDITY
auto t = std::make_tuple(false, false, true);
bool a = get<0>(t); // Now the compiler knows to use ADL!
bool b = std::get<0>(t); // okay
http://ideone.com/fb8Ai
Обратите внимание, что not_used_for_anything
в приведенном выше просто является механизмом безопасности. Он предназначен для неполного типа, который никогда не завершается. Опущение это работает также, но небезопасно, потому что оно может столкнуться с подписью, которую вы, возможно, захотите.
template< typename >
void get() = delete;
http://ideone.com/WwF2y
Примечание: приведенная выше цитата из Стандарта ненормативна, что означает, что, по мнению Комитета, мы сможем понять это без объяснения причин, поскольку это подразумевается остальной частью языка и грамматики, в частности факт, что 3.4.2 ничего не говорит о поиске шаблонов-идентификаторов. Да, правильно!