Jes
Jes

Reputation: 2684

Extract a type from a templated class

I am implementing a type extractor extract_type<Class, nth-type> for any templated class. An example usage is shown as follows:

template <int, short, float, double, char> class C;

extract_type<C, 0>::type => int
extract_type<C, 1>::type => short
extract_type<C, 2>::type => float
extract_type<C, 3>::type => double
extract_type<C, 4>::type => char

Here is my implementation.

// extract_type: recursive definition.
template <template <typename...> class C, size_t idx, typename T, typename... RestT> 
struct extract_type;

// extract_type: base
template <template <typename...> class C, typename T, typename... RestT>
struct extract_type< C<RestT...>, 0, RestT... > { 
  using type = T;
};


// extract_type: recursive definition.
template <template <typename...> class C, size_t idx, typename T, typename... RestT>
struct extract_type : public extract_type< C<RestT...>, idx-1, RestT... > { 
};

However, the compiler complains about

type/value mismatch at argument 1 in template parameter list for 'template class C, long unsigned int idx, class T, class ... RestT> struct OpenCluster::extract_type' struct extract_type< void, 0, RestT...>

How can I get this resolved?

Upvotes: 1

Views: 1020

Answers (2)

AlphaRL
AlphaRL

Reputation: 1629

Here is my implementation.

#include "iostream"

template<class ...Ts> struct C {};

template<int N, class ...Ts>
struct extract_type_impl;

template<class C, int N>
struct extract_type;

template<template<class ...> class C, class ...Ts, int N>
struct extract_type<C<Ts...>, N> {
  typedef typename extract_type_impl<N, Ts...>::type type;
};

template<int N, class T, class ...Ts>
struct extract_type_impl<N, T, Ts...> {
  typedef typename extract_type_impl<N - 1, Ts...>::type type;
};

template<class T, class ...Ts>
struct extract_type_impl<0, T, Ts...> {
  typedef T type;
};

int main() {
  static_assert(std::is_same<extract_type<C<int, float, char, double>, 3>::type, double>::value, "");
  // static_assert(std::is_same<extract_type<C<int, float, char, double>, 3>::type, int>::value, "");
}
  • Get the parameter lists of C
  • Get n-th parameter

Live Demo

Upvotes: -1

skypjack
skypjack

Reputation: 50540

Do you mean something like that (minimal, working example)?

#include<tuple>
#include<iostream>
#include<type_traits>

template<int, typename...>
struct extract_type;

template<int N, typename T, typename... O, template<typename...> typename U>
struct extract_type<N, U<T, O...>>: extract_type<N-1, U<O...>> { };

template<typename T, typename... O, template<typename...> typename U>
struct extract_type<0, U<T, O...>> { using type = T; };

int main() {
    using MyTuple = std::tuple<int, double, char>;
    // true
    std::cout << std::is_same<extract_type<1, MyTuple>::type, double>::value << std::endl;
    // false
    std::cout << std::is_same<extract_type<2, MyTuple>::type, double>::value << std::endl;
}

This one would be your code (fixed and working version) instead:

#include<tuple>
#include<iostream>
#include<type_traits>

// extract_type: recursive definition.
template <template <typename...> class C, size_t idx, typename T, typename... RestT> 
struct extract_type;

// extract_type: base
template <template <typename...> class C, typename T, typename... RestT>
struct extract_type< C, 0, T, RestT... > { 
    using type = T;
};

// extract_type: recursive definition.
template <template <typename...> class C, size_t idx, typename T, typename... RestT>
struct extract_type : public extract_type< C, idx-1, RestT... > { };

int main() {
    // true
    std::cout << std::is_same<extract_type<std::tuple, 1, int, double, char>::type, double>::value << std::endl;
    // false
    std::cout << std::is_same<extract_type<std::tuple, 2, int, double, char>::type, double>::value << std::endl;
}

Pretty ugly, isn't it?

The problem is that you define it as if to pass the template class separated from its parameters, so that the former has no role within extract_type.
It means that you could have defined it as:

template <size_t idx, typename T, typename... RestT> 
struct extract_type;

So, it would have been used as:

extract_type<1, int, double, char>::type

With the same result: double.

Got the error in your example (apart the syntactic one, of course)?

Upvotes: 1

Related Questions