views:

90

answers:

1

Hi,

For some complicated reason, I want to convert any supported type T (coming from a template) to a list of types I have chosen. For this, I tried using a template structure named "Convert". For example:

Convert<short>::type should be int
Convert<int>::type should be int
Convert<char>::type should be int
Convert<float>::type should be double
Convert<double>::type should be double
Convert<const char*>::type should be std::string
Convert<std::string>::type should be std::string
etc.

Those above are easy to implement using template specialisation. But there is one case that is causing problems :

Convert<T>::type where T is a functor should be T

To handle this, I think I have to use SFINAE but I can't manage to make it compile.

The code below gives me "partial specialization cannot match argument list for primary template" (ie. writing "Convert" is forbidden) :

template<typename T, typename = decltype(&T::operator())>
struct Convert<T>       { typedef T type; };

And this one gives me "template parameter not used or deducible in partial specialization" (ie. it thinks that T is not used) :

template<typename T>
struct Convert<typename std::enable_if<std::is_function<typename T::operator()>::value,T>::type>
 { typedef T type; };

I have no idea of what to do, all my attempts result in one of the two errors above.

EDIT: I would like to catch other generic things using the same model, so I can't just write "typedef T type" in the non-specialized structure.

Thanks

+2  A: 

I'd suggest you use the first approach, but to make it work, you'll have to

Declare the master template with one unused template-argument:

template <class T, class = void> Convert;

Add a void parameter to all specializations of the template you use now.

Define your "functor specialization" like this:

template<typename T, typename std::enable_if<std::is_function<typename T::operator()>::value,void>::type>

That means you make the second argument void if it is a functor (so it matches the default template argument) or nonexisting if it isn't.

BTW why do you use typename in typename T::operator()? AFAIK, operator() is not a type.

jpalecek
Great idea, thanks. Apparently I don't even need to add `void` to my other specialisations. However the compiler uses the unspecialized structure for the moment, I'll try to make it work.
Tomaka17
Tomaka17
`Convert<T, typename std::enable_if<true,void>::type>` is working, so there must be a problem in my condition
Tomaka17
The code in my second commentary works on g++ but not on MSVC++, however I made it work on both compiler by creating a "IsFunctor" type inspired by http://stackoverflow.com/questions/257288/possible-for-c-template-to-check-for-a-functions-existence/257382#257382 Thanks
Tomaka17