I'm trying to implement a template class (named Get<>
here) that, given a structure H
, the type Get<H>::type
is the H
itself if the qualified-id H::der
doesn't exist, and is Get<H::der>::type
otherwise. I can't understand what's wrong with the following code:
#include <iostream>
#include <typeinfo>
using namespace std;
template<class U, class V = void>
struct Get
{
static const char id = 'A';
typedef U type;
};
template<class U>
struct Get<U,typename U::der>
{
static const char id = 'B';
typedef typename Get<typename U::der>::type type;
};
struct H1
{ };
struct H2
{ typedef double der; };
struct H3
{ typedef void der; };
struct H4
{ typedef H2 der; };
void print(char id, const char* name)
{
cout << id << ", " << name << endl;
}
int main(int , char *[])
{
print(Get<H1>::id, typeid(Get<H1>::type).name()); // prints "A, 2H1", OK
print(Get<H2>::id, typeid(Get<H2>::type).name()); // prints "A, 2H2", why?
print(Get<H3>::id, typeid(Get<H3>::type).name()); // prints "B, v" , OK
print(Get<H4>::id, typeid(Get<H4>::type).name()); // prints "A, 2H4", why?
}
I'd like some help to make this code behave as expected. More specifically, I wish that Get< H2 >::type
was equal to double
, and the same for Get< H4 >::type
.
The template Get<>
has a default template parameter -- this is very dangerous. Depending on whether V
is equal int
, void
or double
you get different results. This is what happens:
Get<H2>::type
is Get<H2, void>
on the first place (with id='A'
). Now comes the check, whether there is an specialization of it. Your B is Get<U,typename U::der>
which becomes Get<U, double>
. But this doesn't match whith Get<H2, void>
, so A
is chosen. Things get interesting with Get<H2>::type
. Then the variant B is also Get<U, void>
and provides a better match. However, the approach can't work for all types.
This is how I would have implemented Get
:
template<class U>
class Get
{
template <typename T, typename = typename T::der>
static typename Get<typename T::der>::type test(int);
template <typename T>
static T test(...);
public:
typedef decltype(test<U>(0)) type;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With