1

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?

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Jes
  • 2,614
  • 4
  • 25
  • 45
  • Related: http://stackoverflow.com/questions/16928669/how-to-get-n-th-type-from-a-tuple – kennytm Mar 31 '16 at 17:26
  • `template class C` is a template template parameter, which suddenly becomes a type template parameter in a spacialization. Moreover, ``, these are non-type template parameters, so `class C` can't even be matched against `template class C` – Piotr Skotnicki Mar 31 '16 at 17:28
  • 1
    Are you sure you want `extract_type`, and not `extract_type, 1>` ? – Piotr Skotnicki Mar 31 '16 at 17:31

2 Answers2

1

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)?

skypjack
  • 49,335
  • 19
  • 95
  • 187
  • Hi Skypjack. Thanks for the help!! – Jes Apr 01 '16 at 17:17
  • @Jes You used `typename... RestT` in your code. What does it mean? It's a [parameter pack](http://en.cppreference.com/w/cpp/language/parameter_pack), what else? – skypjack Apr 01 '16 at 17:20
  • Yes. I understood. There is a mistake I made in declaring the template specialization. – Jes Apr 01 '16 at 17:41
-1

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

Shangtong Zhang
  • 1,579
  • 1
  • 11
  • 18
  • What against inheritance? – skypjack Apr 01 '16 at 18:03
  • @skypjack : Some compilers (\*cough\* VC++ \*cough\*) give warnings when a type's inheritance tree exceeds a certain number of characters. Other than that, it's just personal preference AFAIK. – ildjarn Apr 12 '16 at 00:19