4

I think I understand by now why partial function templates are considered confusing and unnecessary, and are thus not allowed by the C++ standard. I would however appreciate some help with re-phrasing the following function w/o partial specialization. FWIW, the function is a member of a non-specialized class:

template <typename IMPL, typename RET>
RET call (functor <IMPL> func, 
          IMPL * impl)
{ 
  return func.call (impl);
}

template <typename IMPL>
void call <IMPL, void_t> (functor <IMPL> func, 
                          IMPL * impl) 
{ 
  func.call (impl);
}

The problem here is that I can't overload on the function's return type. Also, the typename I want to specialize on is not used as function parameter - another reason why overloading does not help. Yes, I could introduce a dummy parameter, to force overloading, but that is ugly, isn't it?

Finally, why the heck isn't 'void' a type in C++? That would make things so much more consistent... But I am probably missing the complete picture...

Peer Gynt
  • 55
  • 5
  • 2
    `void` is a type in C++, just not a data-type (i.e. you can have `void` functions, but not `void` data objects). Instead, if you find it necessary, you can try to use `void*` (casting an existing data-type) for data – RageD Aug 11 '11 at 21:05
  • 1
    You don't need to specialize for `void`. It's perfectly OK to `return` a function call whose return type is `void`. – Praetorian Aug 11 '11 at 21:10
  • Wow - how could I miss that 'return void' thing? Seems I learned something wrong some time in the past, and it stuck! Big thanks for the many useful answers, extremely helpful! :-) – Peer Gynt Aug 11 '11 at 21:26
  • Thanks again - code looks much cleaner now, everything works nicely, and I learned a number of things from your answers :-) – Peer Gynt Aug 11 '11 at 21:57

5 Answers5

7

I believe that, firstly, if you have a function that returns void, then it's perfectly legitimate to return a void expression- such as the call of another function that returns void, and secondly, void is a full type in C++ and you can pass it to templates as much as you like.

Puppy
  • 144,682
  • 38
  • 256
  • 465
2

If your functor template class already has a typedef for RET, you can do this instead:

template <typename IMPL>
typename functor<IMPL>::RET call (functor <IMPL> func, 
          IMPL * impl)
{ 
  return func.call (impl);
}

and not bother with the overload. Also, what is the compiler you are using? All standard-conformant compilers allow you to return the result of a void function from a void function.

MSN
  • 53,214
  • 7
  • 75
  • 105
  • "*VC++ 2010 allows you to return the result of a void function from a void function.*" All standard-conformant compilers do. – ildjarn Aug 11 '11 at 21:07
  • @ildjarn, yes, well... updating with that phrasing. – MSN Aug 11 '11 at 21:09
2

The general solution for partial specialization of functions involves using a helper class template with the same template arguments, with a single method with the same arguments as your function. The template class can then be partially specialized.

In your case, however, I would think you should be able to use void as your return type, as noted by the other answers.

Dave S
  • 20,507
  • 3
  • 48
  • 68
2

First,

template <typename IMPL, typename RET>
RET call (functor <IMPL> func, 
          IMPL * impl)
{ 
  return func.call (impl);
}

should really be

template <typename RET, typename IMPL>
RET call (functor <IMPL> func, 
          IMPL * impl)
{ 
  return func.call (impl);
}

(I inversed RET and IMPL in the template argument list) so that you can call the function like

call<int>(f, impl);

instead of having to type

call<impl_type, int>(f, impl);

Indeed, the compiler cannot deduce RET, so you have to provide it yourself.

Second, you don't need to overload for void, since it is OK to return a void expression. If you want, you can add an overload:

template <typename IMPL>
void call(functor<IMPL> func, IMPL* impl)

and use call(f, impl) when calling this overload.

If you have access to C++0x, consider using decltype.

Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
1

You could do this by using function overloading:

template <typename IMPL, typename RET>
RET call (functor <IMPL> func, 
          IMPL * impl)
{ 
  return func.call (impl);
}

template <typename IMPL>
void call (functor <void_t> func, void_t * impl) 
{ 
  func.call (impl);
}

Also, void is a type in C++; what makes you think that it isn't?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • This probably misses though, what the template parameter for functor stands for (apparently the type of the pointer passed to the `call` method). – UncleBens Aug 11 '11 at 21:22