Question

Consider the following classes:

template<class T, int...> struct MyClass1 {};
template<class T, unsigned int...> struct MyClass2 {};
template<class T, long long int...> struct MyClass3 {};
template<class T, unsigned long long int...> struct MyClass4 {};

I cannot modify these classes.

Is it possible to write an helper class or function or something, that will return the type of the variadic list:

something<MyClass1>::type (-> int)
something<MyClass2>::type (-> unsigned int)
something<MyClass3>::type (-> long long int)
something<MyClass4>::type (-> unsigned long long int)

and size_t if the variadic list is empty ?

Was it helpful?

Solution

I couldn't come up with a way to define one generic metafunction that does it, but here is a possible workaround:

#include <iostream>
#include <type_traits>

using namespace std;

// PRIMARY TEMPLATE

template<typename T>
class something
{
};

// SPECIALIZATIONS FOR int

template<typename T, int... U, template<typename, int...> class L>
class something<L<T, U...>>
{
public:
    typedef int type;
};

template<typename T, template<typename, int...> class L>
class something<L<T>>
{
public:
    typedef size_t type;
};

// SPECIALIZATIONS FOR unsigned int

template<typename T, unsigned int... U, template<typename, unsigned int...> class L>
class something<L<T, U...>>
{
public:
    typedef unsigned int type;
};

template<typename T, template<typename, unsigned int...> class L>
class something<L<T>>
{
public:
    typedef size_t type;
};

/* ... OTHER SPECIALIZATIONS ... */

struct A {};
struct B {};

int main()
{
    static_assert(is_same<something<MyClass1<A, 1, 2>>::type, int>::value, "Error!");
    static_assert(is_same<something<MyClass1<A>>::type, size_t>::value, "Error!");
    static_assert(is_same<something<MyClass2<B, 1U, 2U, 3U>>::type, unsigned int>::value, "Error!");
    static_assert(is_same<something<MyClass2<B>>::type, size_t>::value, "Error!");
    return 0;
}

I tried to write only single specialization that would cover all cases, like this:

template<typename U, typename T, U... V, template<typename, U...> class L>
class something<L<T, V...>>
{
public:
    typedef U type;
};

But Clang 3.2 complains that the type of U cannot be deduced, so this specialization of get_type will never be used. So if you follow this approach you will have to explicitly define each specialization. This may or may not be acceptable depending on your use cases. Hope it helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top