tmlen
tmlen

Reputation: 9090

Accessing template arguments from specialization

template<typename T, typename U>
struct A;

template<std::size_t I>
struct A<int, char[I]> {
    using pointer = T*; // does not compile
};

int main() {
    A<int, char[3]> a;    
}

Is there any way to access the type T (= int) from inside the class template specialization A<int, char[I]>, without explicitly writing the type that is has in the specialization?

Upvotes: 2

Views: 121

Answers (3)

p0pa
p0pa

Reputation: 64

Simply,

#include <type_traits>

template<class T, class U>
struct foo;

template<class T, std::size_t Index>
struct foo<T, char[Index]>
{
    using type = T;
};

int
main()
{
    static_assert(std::is_same<foo<int, char[3]>::type, int>::value, "");
}

Upvotes: -1

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275405

Something like this:

template<class T, class U, class=T, class=U>
struct A;

template<std::size_t I, class T, class U>
struct A<int, char[I], T, U> {
  using pointer = T*;
};

works. If someone actually passes a type for the second T and U problems develop, but...

Another approach is:

template<class T, class U>
struct A;

// get args from an instance!
template<class A>
struct A_Args;
template<class T_, class U_>
struct A_Args<A<T_,U_>> {
  using T = T_; using U = U_;
};
template<class A>
using A_T = typename A_Args<A>::T;
template<class A>
using A_U = typename A_Args<A>::U;

// reflect on our troubles:
template<std::size_t I>
struct A<int, char[I]> {
  using pointer = A_T<A>*;
};

where we have a using alias that extracts args from a generic A which we use within the specialization.

This version can be made generic with an interface like:

template<std::size_t I, class Instance>
struct nth_template_arg;
template<std::size_t I, class Instance>
using nth_template_arg_t=typename nth_template_arg<I, Instance>::type;

with the note it will only work with templates that only take type arguments. (implementation left as an exercise. I'd probably use tuple_element for a first pass; using tuples has the downside that they are heavy types, and metaprogramming with heavy types sucks performance and sometimes causes other problems.)

Upvotes: 7

LibertyPaul
LibertyPaul

Reputation: 1167

You can try this:

template<typename T, typename U, std::size_t I>
struct A{
    using pointer = T*;
};

Upvotes: -2

Related Questions