4

Considering a template function like below how is it possible to do explicitly specialize one version of function for multiple types:

template <typename T>
void doSomething(){
 //whatever
}

The intention is to have one specialization instead of multiple following ones because //something is the same:

void doSomething<int>(){
 //something
}
void doSomething<float>(){
 //something
}
void doSomething<double>(){
 //something
}

any method to achieve one specialization?

Pooria
  • 2,017
  • 1
  • 19
  • 37

3 Answers3

4

You can't make template function specialization. But you could delegate the implementation in a helper class, that can be used from your function. Some skeleton code:

Implement a template class and specialize it:

template< typename T, bool isArithmetic>
struct Something { void operator()() { ... } };

template< typename T, true>
struct Something { void operator()() { ... do something specialized for arithmetic types; } }

Then use it in the template function:

template< typename T>
void myFunction()
{
   Something<T, IsArithmetic<T>::value>()();
}

Where IsArithmetic is a class that provides the information about type T (selector). You can find such type info in boost libraries, for example.

Cătălin Pitiș
  • 14,123
  • 2
  • 39
  • 62
  • 1
    You absolutely can, using `enable_if` and overloading. But I agree that delegating to a (specialized) struct is often cleaner. – Konrad Rudolph Nov 25 '10 at 18:59
  • @Konrad Rudolph_In fact the only way seems to be using enable_if. – Pooria Nov 25 '10 at 20:36
  • @Pooria: Yes - the “using `enable_if` and overloading” was referring to *one* single technique, not two different techniques. It should also be noted that behind the scenes, `enable_if` is merely using SFINAE in combination with specialized helper struct’s, much like in Cătălin’s example. – Konrad Rudolph Nov 25 '10 at 20:55
1

You could just have a kind of doSomethingImpl function.

template<typename T> doSomethingImpl() {
    // whatever
}
template<typename T> doSomething() {
    // something else
}
template<> doSomething<float>() {
    doSomethingImpl<float>();
}
template<> doSomething<int>() {
    doSomethingImpl<int>();
}

It's also possible to specialize more generically, using SFINAE and std::is_numeric<T>, for example.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • You're still doing separate specializations per each type. – Pooria Nov 25 '10 at 19:03
  • @Pooria: But you don't have to maintain the code for each of them separately. I said in my answer that if you were looking for something even more generic, you could try out std::is_numeric – Puppy Nov 25 '10 at 22:41
  • @Puppy Then could you give an example on how to use std::is_numeric ? – mxmlnkn Nov 09 '16 at 17:08
1

using c++ 2011 (option -std=c++11), this works well:

#include <iostream>

template <typename T>
struct unsignedObject
{
    unsignedObject() {
        std::cout << "instanciate a unsignedObject\n";
    }
};

struct signedObject
{
    signedObject() {
        std::cout << "instanciate a signedObject\n";
    }
};

template <typename T>
struct objectImpl
{
    typedef unsignedObject<T> impl; // optional default implementation (the line can be removed)
};

template <> struct objectImpl<unsigned char>  { typedef unsignedObject<unsigned char>  impl; };
template <> struct objectImpl<unsigned int>   { typedef unsignedObject<unsigned int>   impl; };
template <> struct objectImpl<unsigned short> { typedef unsignedObject<unsigned short> impl; };
template <> struct objectImpl<double>         { typedef signedObject   impl; };
template <> struct objectImpl<int>            { typedef signedObject   impl; };
template <> struct objectImpl<short>          { typedef signedObject   impl; };
template <> struct objectImpl<char>           { typedef signedObject   impl; };

template <typename T>
using object = typename objectImpl<T>::impl;

int main(void)
{
    object<int> x;    // x is a signedObject.
    object<double> y; // y is a signedObject.
    object<unsigned short> z; // z is a unsignedObject.
    return 0;
}