7cows
7cows

Reputation: 5044

Getting at template parameter types of a template type

I have a question about templates and it is in the code:

template<typename T>
struct foo {
  T t;
};

template<typename FooType>
struct bar {
  T t; //<- how to get T here (preferably without using typedef in foo)
};

Upvotes: 0

Views: 180

Answers (3)

Kerrek SB
Kerrek SB

Reputation: 477512

Here's a generic template argument type extractor:

#include <tuple>

template <typename> struct tuplify;

template <template <typename...> class Tpl, typename ...Args>
struct tuplify<Tpl<Args...>>
{
    using type = std::tuple<Args...>;
};

template <typename T, unsigned int N>
using get_template_argument
    = typename std::tuple_element<N, typename tuplify<T>::type>::type;

Usage:

get_template_argument<std::vector<int>, 1> a;  // is a std::allocator<int>

Or in your case:

get_template_argument<FooType, 0> t;

Upvotes: 5

AnT stands with Russia
AnT stands with Russia

Reputation: 320719

If you don't want or can't add a typedef to foo, you can additionally write an independent "extractor" template

template <typename T> struct ExtractT;
template <typename T> struct ExtractT<foo<T> > {
  typedef T type;
};

and use it as

template<typename FooType>
struct bar {
  typename ExtractT<FooType>::type t;
}; 

You can take that ExtractT one step further and decouple it from foo

template <typename T> struct ExtractT;
template <template <typename> class C, typename T> struct ExtractT<C<T> > {
  typedef T type;
};

and so on until you reinvent something from Boost or C++11 standard library :) BTW, this feels like something that should already be available in form of a more generic solution....

Upvotes: 1

Andy Prowl
Andy Prowl

Reputation: 126542

If I understood your question correctly, you could use template specialization as follows. Given your foo<> class template:

template<typename T>
struct foo {
  T t;
};

Define a bar<> primary template and a corresponding specialization this way:

template<typename FooType>
struct bar;

template<typename T>
struct bar<foo<T>> {
  T t; // T will be int if the template argument is foo<int>
};

Under the assumption that you are always supposed to instantiate bar by providing an instance of foo<> as the type argument, you can leave the primary template undefined.

The specialization will match the foo<T> pattern, thus giving you the type with which foo<> is instantiated in T.

Here is how you could test the validity of this approach with a simple program:

#include <type_traits>

int main()
{
    bar<foo<int>> b;

    // This will not fire, proving T was correctly deduced to be int
    static_assert(std::is_same<decltype(b.t), int>::value, "!");
}

Here is the corresponding live example.

Upvotes: 1

Related Questions