7

I often want to get the decltype of a class template argument in order to use it further, like in a loop which I have stripped and simplified to show my problem:

template <typename T>
class Foo {
public:
    T type; //This is my hack to get decltype of T
};

template <typename T>
class Bar {
public:

};

int main() {
    for(auto& foo : fs) {
        //Is there some way to get the decltype of the template without having to refer to some arbitrary T member of Foo?
        auto bar = someFunction<decltype(foo.type)>();
    }
}

Is there a way to get the decltype of the template argument without doing this hack? If not, what is the best workaround to get the decltype of such a value?

Gerard
  • 2,832
  • 3
  • 27
  • 39
  • It is just a vector containing those objects, sorry could have left it out (or explained it). The point was that I use auto because I actually iterate over a tuple and then over the vector (fs), which is why I really want to use auto and then extract the template type from it. – Gerard Dec 09 '14 at 17:15
  • This detail is critical. Vectors are homogeneous. – Lightness Races in Orbit Dec 09 '14 at 17:22
  • 1
    Possible duplicate of [Can one access the template parameter outside of a template without a typedef?](https://stackoverflow.com/questions/3696286/can-one-access-the-template-parameter-outside-of-a-template-without-a-typedef) – Ciro Santilli OurBigBook.com Jan 07 '18 at 23:26

2 Answers2

10

You may create a type_traits:

template <typename C>
struct get_template_type;

template <template <typename > class C, typename T>
struct get_template_type<C<T>>
{
    using type = T;
};

and then you use it (assuming C = Foo<T>, you will have T)

typename get_template_type<C>::type

Live example

EDIT: For classes with multiple template parameter, to retrieve the first one:

template <template <typename > class C, typename T, typename ... Ts>
struct get_template_type<C<T, Ts...>>
{
    using type = T;
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • This won't work for templates with default args or templates with more than one argument, such as `std::vector`. – rubenvb Dec 09 '14 at 15:57
  • Could you add an example on how to use it in my scenario? I thought I had it, but I don't quite. – Gerard Dec 10 '14 at 11:33
  • Very nice, thank you. one last thing if you could indulge me; would there be a way to make this even shorter, could I create a function that returns a typedef or something else? – Gerard Dec 10 '14 at 21:05
  • @Gerard: to avoid the `typename ..::type`, you may add alias `template using get_template_type_t = typename get_template_type::type` (same for `decay_t` (which should exist in C+++14)). To remove completely `decay`, you may add specializations, something like `template struct get_template_type : get_template_type {};` – Jarod42 Dec 11 '14 at 08:08
1

EVerything in the Standard library just has class-local typedefs:

template<typename T>
struct Bla
{ using value_type = T; }

So you can do:

template<typename T>
void f(const T& t)
{
  typename T::value_type some_var_with_template_type;
}

Alternatively, you can modify the calling function:

template<template<typename> class Class, typename T>
void f(const Class<T>& c)
{
  T some_var_with_template_type;
}

But that would impose limitations on usability and generality. Because for example, if there were a Class with more than one template param, this would fail (although variadic templates could be used to work around this). Variadic template version:

template<template<typename, typename...> class Class, typename T, typename... ArgTypes>
void f(const Class<T, ArgTypes...>& t)
{
  T some_var_of_template_type;
}

Note how the value_type typedef is by far the cleanest and most idiomatic solution.

Some code to show how the functions would need to be written and used.

rubenvb
  • 74,642
  • 33
  • 187
  • 332