Template-specialization for one out of multiple templates in C++

Viewed 41

the header mycomputationclass.h:

#pragma once
template<typename numberType, bool increaseByOne>
class MyComputationClass
{
   numberType a = 1;
   numberType b = 2;
   numberType compute();
};

#include mycomputationclass.hpp

the header implementation file mycomputationclass.hpp:

#pragma once
#include mycomputationclass.h

template<typename numberType, bool increaseByOne>
numberType MyComputationClass<numberType, increaseByOne>::compute()
{
   return a + b;
}
template<typename numberType>
numberType MyComputationClass<numberType, true>::compute()
{
   return a + b + static_cast<numberType>(1);
}

the error:

 error: invalid use of incomplete type ‘class MyComputationClass<numberType, true>’
 numberType MyComputationClass<numberType, true>::compute()
                                                          ^

All topics related to specialisation I find are using only one template. Can anyone please help me out here?

1 Answers

First of all please see Why can templates only be implemented in the header file?. Now, your problem doesn't stem from the above, but nevertheless you should strongly consider if you indeed want to implement the template in the cpp file. I suspect you do not.

Anyway the problem you are asking about is that you are trying to define a method of a specialized class template which you haven't specialized.

There are a couple of options here.

  • You can specialize the class template, repeating the whole body

    template<typename numberType>
    class MyComputationClass<numberType, true>
    {
       numberType a = 1;
       numberType b = 2;
       numberType compute();
    };
    
  • You can create a base class template with all the common code and have derived classes templates with only the parts you need to specialize

  • In C++17 you can use if constexpr:

    template<typename numberType, bool increaseByOne>
    numberType MyComputationClass<numberType, increaseByOne>::compute()
    {
        if constexpr (increateByOne)
            return a + b + 1;
        else
            return a + b;
    }
    
  • In C++20 you can use the requires clause:

    template<typename numberType, bool increaseByOne>
    class MyComputationClass
    {
       numberType a = 1;
       numberType b = 2;
       numberType compute() requires increaseByOne
       {
           return a + b + 1;
       };
        numberType compute() requires (!increaseByOne)
       {
           return a + b;
       };
    };
    
  • In old C++ in your case you can use simple if. Since increaseByOne is known at compile time the compiler will optimize it as if it were if constexpr. The only problem you would have is if you returned different types on each branch or have some code that is invalid on one of the branches. So simple if is a solution here:

    template<typename numberType, bool increaseByOne>
    numberType MyComputationClass<numberType, increaseByOne>::compute()
    {
        if (increateByOne)
            return a + b + 1;
        else
            return a + b;
    }
    
Related