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

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

http://ideone.com/fb8Ai

Обратите внимание, что not_used_for_anything в вышесказанном это просто механизм безопасности. Он предназначен для неполного типа, который никогда не завершается. Пропускать это тоже работает, но небезопасно, потому что может столкнуться с подписью, которую вы можете захотеть.

template< typename >
void get() = delete;

http://ideone.com/WwF2y

Примечание: приведенная выше цитата из Стандарта является ненормативной, что означает, что, по мнению Комитета, мы сможем выяснить это без объяснения причин, поскольку это подразумевается остальной частью языка и грамматики, в частности тем, что 3.4.2 ничего не говорит о поиске идентификаторов шаблонов. Да правильно!

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