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

Получение элемента из кортежа

Возможный дубликат:
Почему 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

Почему?

4b9b3361

Ответ 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 ничего не говорит о поиске шаблонов-идентификаторов. Да, правильно!