Michbeckable
Michbeckable

Reputation: 1881

C++ - Specialize member function for Template Class

I have a class-template representing a mathematical vector:

template<class Value_T, unsigned int N>
class VectorT
{
public:

    void Normalize()
    {
        // normalize only double/float vectors here
    }

private:
    // elements in the vector
    value_type elements[N];     

    // the number of elements
    static const size_type size = N;
};

I would like to have a special treatment for vectors of integer types, as a vector normalization is not possible on this types. So I need a seperate (may be specialization) for the Normalize method that depends on the template argument Value_T of the VectorT class-template.

I have tried to use template specialization in different ways but did not get it to work. Do I have to make the Normalize function a template function itself? At the moment it just a normal member-method.

Upvotes: 0

Views: 730

Answers (4)

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48447

You can solve this with a tag dispatching technique:

#include <iostream>
#include <type_traits>

template<class Value_T, unsigned int N>
class VectorT
{
public:
    void Normalize()
    {
        using tag = std::integral_constant<bool
                                         , std::is_same<Value_T, double>::value
                                           || std::is_same<Value_T, float>::value>;  

        // normalize only double/float vectors here
        Normalize(tag());
    }

private:
    void Normalize(std::true_type)
    {
        std::cout << "Normalizing" << std::endl;
    }

    void Normalize(std::false_type)
    {
        std::cout << "Not normalizing" << std::endl;
    }

    // elements in the vector
    Value_T elements[N];     

    // the number of elements
    static const std::size_t size = N;
};

DEMO

Upvotes: 3

AnT stands with Russia
AnT stands with Russia

Reputation: 320371

Yes, you can independently specialize a specific member function of a template class. However, function templates (including member function templates) do not allow partial specializations. Function templates only support explicit specializations. An explicit specialization in your case that would look as follows

// Header file

template<class Value_T, unsigned int N>
class VectorT
{
public:

  void Normalize()
  {
      // normalize only double/float vectors here
  }
  ...
};

// Declare an explicit specialization for <int, 5>
template <> void VectorT<int, 5>::Normalize();

and then

// Implementation file

// Define the explicit specialization for <int, 5>
template <> void VectorT<int, 5>::Normalize()
{
   ...
}

However, explicit initialization is not what you need, apparently, since you want to "fix" the type only and leave the size flexible, i.e. you need a partial specialization. This can be done using the std::enable_if functionality of C++11 (as shown in other answers) as well as through some basic tricks of C++98.

Of course if your class is relatively lightweight, i.e. it does not have much generic code besides that Normalize, you can simply partially specialize the whole class. It will take just a bit more typing.

Upvotes: 1

Kastaneda
Kastaneda

Reputation: 749

Also you can use std::enable_if<>

#include <iostream>
#include <type_traits>

template<class Value_T>
class VectorT
{
public:
    template<class T = Value_T>
    typename std::enable_if<std::is_integral<T>::value, void>::type
    Normalize()
    {
        std::cout << "Not normalizing" << std::endl;
    }

    template<class T = Value_T>
    typename std::enable_if<!std::is_integral<T>::value, void>::type
    Normalize()
    {
         std::cout << "Normalizing" << std::endl;
    }
};

int main()
{
    VectorT<int> vint;
    VectorT<double> vdouble;

    vint.Normalize();
    vdouble.Normalize();

    return 0;
}

DEMO

Upvotes: 1

Jarod42
Jarod42

Reputation: 217085

It seems that you want forbid Normalize for other type than floating point, so you may use static_assert to have good error message:

template<class Value_T, unsigned int N>
class VectorT
{
public:

    void Normalize()
    {
        static_assert(std::is_floating_point<Value_T>::value, "Normalize available only for floating point");
        // normalize only double/float vectors here
    }

// Other stuff

};

Upvotes: 1

Related Questions