saga
saga

Reputation: 2113

Partial specialization does not use any of its template parameters

I'm trying to implement tuples with template metaprogramming, but am having problems with the indexing function get. The implementation of Tuple type is this:

template<typename A, typename... B>
class Tuple : Tuple<B...> {
    private:
        A val;
    public:
        using Base = Tuple<B...>;
        Base* base() {
            return static_cast<Base*>(this);
        }
        const Base* base() const {
            return static_cast<const Base*>(this);
        }
        Tuple(A a, B... b): Base(b...), val(a) { }
        A first() {
            return val;
        }
};

template<class A>
class Tuple<A> {
    private:
        A val;
    public:
        Tuple(A a): val{a} {}
        A first() {
            return val;
        }
};

The implementation of get structure is:

template<int N, class... A>
struct get {
    select<N,A...> operator()(Tuple<A...> t) {
        return get<N-1>()(t.base());
    }
};

template<class R, class... A>
struct get<0> {
    R operator()(Tuple<R, A...> t) {
        return t.first();
    }
};

This is the error compiler is giving me:

tuple.cpp:53:8: error: partial specialization of 'get' does not use any of its template parameters
struct get<0> {
       ^
1 error generated.

Why am I getting this error? How can I correct it?

Note: select<N,A...> is a type function which selects type at Nth index from A.

Upvotes: 3

Views: 1426

Answers (2)

max66
max66

Reputation: 66190

Maybe you have to partial specialize get as follows

template<class R, class... A>
struct get<0, R, A...> {
    R operator()(Tuple<R, A...> t) {
        return t.first();
    }
};

I mean... get<0, R, A...>, not get<0>

But you have also to modify the main get to call the following call with the correct type list, so

template<int N, typename A0, typename ... As>
struct get {
    auto operator()(Tuple<A0, As...> t) {
        return get<N-1, As...>()(t.base());
    }
};

Otherwise you can also demand the types management to a template version of the operator() and maintain only the int N value for get

template <int N>
struct get
 {
   template <typename Tpl>
   auto operator() (Tpl t)
      -> decltype( get<N-1>()(t.base()) )
    { return get<N-1>()(t.base()); }
 };

template<>
struct get<0>
 {
   template <typename Tpl>
   auto operator() (Tpl t)
      -> decltype ( t.first() )
    { return t.first(); }
 };

Starting from C++14 you can avoid the decltype() part.

Off topic suggestion: avoid the use of names that can collide with std namespace names.

Maybe myGet and myTuple instead of get and Tuple.

Otherwise you can put all in a personal namespace (so myNs::get and myNs::Tuple.

Upvotes: 1

jfMR
jfMR

Reputation: 24738

Your get's primary template is:

template<int N, class... A>
struct get{ ... };

your get's partial specialization is:

template<class R, class... A>
struct get<0>{ ... };

The specialization is receiving a single template argument, i.e.: 0, but the primary template above takes two template parameters:

  • the non-type template parameter N.
  • the variadic type parameter A.

Besides, how can R be deduced?


Specializing get instead as:

template<class R, class... A>
struct get<0, R, A...>{ ... };

will make possible R to be deduced: it will be deduced to the type of the first element of the passed variadic argument. For example, in:

get<0, int, float, double> foo;

R will be deduced to int.

Upvotes: 1

Related Questions