2

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

Tomaka17
  • 4,832
  • 5
  • 29
  • 38
  • What do you mean "catch other generic things"? – GManNickG Jul 24 '10 at 09:34
  • You need to clarify what you mean by "a functor". Is a function also good? Or is it only function objects? If so, then anything with `operator()` overloaded? Or derived from `std::function_object`? A specific number of parameters? – sbi Jul 24 '10 at 09:42
  • Examples: "Convert::type is int if T is convertible to an int", or "Convert::type is ... if T has a begin and an end function", etc. – Tomaka17 Jul 24 '10 at 09:44
  • @sbi: In the example above I tried to catch function objects with an operator() (any number of parameter) ; I can handle functions with another specialisation – Tomaka17 Jul 24 '10 at 09:46
  • @Tomaka17: have you seen this: http://stackoverflow.com/questions/257288/possible-for-c-template-to-check-for-a-functions-existence/257382#257382? (link changed) – sbi Jul 24 '10 at 09:48
  • @sbi: yeah but this is just a replacement for std::is_function ; even if I have an `has_helloworld` class, `Convert::result,T>::type>` would fail to compile ; not because of has_helloworld but because of this Convert specialisation not allowed – Tomaka17 Jul 24 '10 at 09:51
  • @Tomaka17: Wouldn't `std::is_function::value` have to be spelled `typename std::is_function::value` instead? – sbi Jul 24 '10 at 10:02
  • @sbi: I get an error if I don't specify typename here, but anyway `std::is_member_function_pointer::value` doesn't work either – Tomaka17 Jul 24 '10 at 10:04
  • (sorry, misread your comment) No because std::enable_if expected a bool, not a type – Tomaka17 Jul 24 '10 at 10:12
  • @Tomaka17: Oh, I overlooked that. Anyway, `T::operator()` should certainly not have a `typename`. __Edit:__ I now see that jpalecek has said the same. – sbi Jul 24 '10 at 10:58

1 Answers1

2

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
  • 47,058
  • 7
  • 102
  • 144
  • 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 Jul 24 '10 at 10:49
  • You're maybe right for the typename, anyway I tried several things like `std::enable_if<!std::is_void::value>::type` which I think is correct – Tomaka17 Jul 24 '10 at 10:51
  • `Convert::type>` is working, so there must be a problem in my condition – Tomaka17 Jul 24 '10 at 11:05
  • 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 Jul 24 '10 at 11:12