Получить элемент из кортежа
Возможный дубликат:
Почему 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
Зачем?
2 ответа
Это потому, что вы пытаетесь явно создать экземпляр 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
C++ (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 }
- конец примера] - конец заметки]
ADL не применяется напрямую к идентификаторам шаблонов, таким как get<0>
Таким образом, компилятор на самом деле не начинает этот путь. C++11 §14.8.1/8 (в C++ 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
Обратите внимание, что not_used_for_anything
в вышесказанном это просто механизм безопасности. Он предназначен для неполного типа, который никогда не завершается. Пропускать это тоже работает, но небезопасно, потому что может столкнуться с подписью, которую вы можете захотеть.
template< typename >
void get() = delete;
Примечание: приведенная выше цитата из Стандарта является ненормативной, что означает, что, по мнению Комитета, мы сможем выяснить это без объяснения причин, поскольку это подразумевается остальной частью языка и грамматики, в частности тем, что 3.4.2 ничего не говорит о поиске идентификаторов шаблонов. Да правильно!