No matching function in template instantiation despite it being there

To implement a custom tuple, I have written the following declarations to access an element:

1
2
3
4
5
6
7
template<int N,			/// non-const version
         typename... T>
Select<N, T...>& Estd::get(Estd::tuple<T...>& t);

template<int N,			/// const version
         typename... T>
Select<N, T...>& Estd::get(const Estd::tuple<T...>& t);


Note: The Select<N, T...>& function selects the Nth type of the T... template parameter pack.

I have no problem accessing a required element of a non-const tuple. Eg:

 
cout << Estd::get<3> (t3);	/// t3 is a non-const tuple 



However, when I try accessing an element of a const tuple, I get an error:

 
cout << Estd::get<3> (ct3);	/// ct3 is a const tuple 


The error is:


No matching function for call to 'get(const Estd::tuple<T...>& t)'
template argument deduction/substitution failed
types Estd::tuple<T ...> and const Estd::tuple<int> have incompatible cv-qualifiers


I have analyzed this error and I think the following is what is happening:
When function Estd::get() is invoked with a const tuple<T...>, only the 1st template argument N is specified (3). Therefore the 2nd template arg is deduced as T... (without the const qualifier), since it is the passed tuple which is const, not its encapsulated types T... .

Therefore, the overload of the get() function that takes a non-const tuple is instantiated rather than the overload that takes a const tuple.

I think this is why the problem occurs.

If so, how can I devise a solution?

Thanks.
Last edited on
AS far as the tuple (in isolation) is concerned, there would be no error;
normal overload resolution would come into play.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <tuple>

template < std::size_t N, typename... T > auto& do_get( std::tuple<T...>& tup )
{ std::cout << "non-cost tuple  " ; return std::get<N>(tup) ; }

template < std::size_t N, typename... T > const auto& do_get( const std::tuple<T...>& tup )
{ std::cout << "const tuple  " ; return std::get<N>(tup) ; }


int main()
{
    auto t = std::make_tuple( 1, 2.3 ) ;
    std::cout << do_get<1>(t) << '\n' ; // non-cost tuple  2.3

    const auto ct = std::make_tuple( 4, 5.6 ) ;
    std::cout << do_get<1>(ct) << '\n' ; // const tuple  5.6 
}

http://coliru.stacked-crooked.com/a/a8989f0684be792e
http://rextester.com/EWO15402

The problem may be with the result type Select<N, T...>&
Don't know what that is, but a guess would be that it should be const Select<N, T...>& for the const overload.
Thanks for the reply, Borges.

Actually, the error (in this respect) lay elsewhere - it was a silly mistake : I had forgotten to declare the const overload of the get function within the Estd namespace. Thus, the Estd namespace contained only the non-const overload declaration. Therefore the template declaration of the const overload was just floating around in the source code; it was never instantiated by the compiler, since as far as the compiler was concerned, it didn't exist within the Estd namespace.

I corrected the error by including both overloads within the Estd namespace:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace Estd
{
   /// ...

   /// construct and return an object of type getNth<T, int>
   template<int N,
            typename... T>
   Select<N, T...>& get(tuple<T...>&);

   /// construct and return an object of type getNth<T, int>
   template<int N,		/// this was not declared earlier
            typename... T>		
   const Select<N, T...>& get(const tuple<T...>&);
}


Please note that in the second overload (which takes a const tuple<T...>), the return type is declared as const Select<N, T...>&. This const is also important; else another compilation error ensues.

Finally, the definition of the 2nd overload must tally exactly with the above declaration, else another error would ensue.

Once these measures are taken, everything works perfectly.
Last edited on
Topic archived. No new replies allowed.