Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getting an element from a tuple [duplicate]

Possible Duplicate:
Why doesn't ADL find function templates?

Calling get does not seem to invoke argument dependent lookup:

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 says:

error: 'get' was not declared in this scope

Visual Studio 2010 says:

error C2065: 'get': undeclared identifier

Why?

like image 214
fredoverflow Avatar asked Sep 11 '11 07:09

fredoverflow


People also ask

Can tuple take duplicate values?

Tuples A Tuple represents a collection of objects that are ordered and immutable (cannot be modified). Tuples allow duplicate members and are indexed.

Does tuple remove duplicates?

Method #1 : Using set() + tuple() This is the most straight forward way to remove duplicates. In this, we convert the tuple to a set, removing duplicates and then converting it back again using tuple().

What is tuple duplicate?

We consider the tuple as duplicate if all the attribute values of two rows are the same. Redundancies between attributes and duplicate tuples must be detected.


2 Answers

It's because you attempt to explicitly instantiate get function template, by providing 0 as template argument. In case of templates, ADL works if a function template with that name is visible at the point of the call. This visible function template only helps triggering ADL (it may not be used actually) and then, a best matching can be found in other namespaces.

Note that the function template which triggers (or enable) ADL, need not to have definition:

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 } 

In g(), the name N::get triggers ADL when calling get<0>(s).

Demo : http://ideone.com/83WOW


C++ (2003) section §14.8.1/6 reads,

[Note: For simple function names, argument dependent lookup (3.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (3.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.

[Example:

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]

like image 116
Nawaz Avatar answered Nov 11 '22 03:11

Nawaz


ADL doesn't directly apply to template-id's such as get<0>, so the compiler doesn't really get started down that path. C++11 §14.8.1/8 (in C++03, 14.8.1/6):

[ Note: For simple function names, argument dependent lookup (3.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (3.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.

It goes on to give a short example. So the workaround is quite easy:

#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

Note that the not_used_for_anything in the above is merely a safety mechanism. It's intended to be an incomplete type which is never completed. Omitting it works as well, but is unsafe because it could collide with a signature you might want.

template< typename >
void get() = delete;

http://ideone.com/WwF2y

Note: the above quote from the Standard is non-normative, meaning that in the opinion of the Committee, we would be able to figure this out without explanation, because it's implied by the rest of the language and grammar, particularly the fact that 3.4.2 says nothing about looking up template-ids. Yeah, right!

like image 36
Potatoswatter Avatar answered Nov 11 '22 04:11

Potatoswatter