c++class-templatetemplate-instantiation

Having different specialization of a class template and the specialization definitions have functions with other specializations in its signature


So I have a class template for example in

Template.h

template <typename T>
class Something {
public:

    static_assert(std::is_floating_point<T>::value, "Floating Point only");
};

and I separated the float and double specialization into different .h files

float.h

#include "Template.h"

template<>
class Something<float> {
public:

    std::string Name = "Float";

    void DoSomething() {
        std::cout << "Float Thing\n";
    }
};

and

Double.h

#include "Template.h"

template<>
class Something<float> {
public:

    std::string Name = "Double";

    void DoSomething() {
        std::cout << "Double Thing\n";
    }
};

I include the three files in order in my .cpp file and it works fine

but I need to add another function to the float specialization which takes Something as a parameter

void SayDouble(Something<double> _D) {
    std::cout << _D.Name << '\n';
}

and then include Double.h after template.h and it works but when I try to do the same in Double.h and add a function which takes or returns Something<float> and includes float.h after tempalte.h. it gives me a lot of errors about re-instantiation

 Float.h(17,19): error C2039: 'Name': is not a member of 'Something<double>'
1>Float.h(16): message : see declaration of 'Something<double>'
1>Double.h(7,1): error C2908: explicit specialization; 'Something<double>' has already been instantiated
1>Double.h(19,2): error C2766: explicit specialization; 'Something<double>' has already been defined
1>Float.h(16): message : see previous definition of 'Something<double>'
1>Float.h(19,2): error C2766: explicit specialization; 'Something<float>' has already been defined
1>Float.h(7): message : see previous definition of 'Something<float>

I don't really understand the problem what I guessed is that maybe having an specialization of the template in the functions signature instantiates the template then when it tries to instantiate it again in the definition it gives "has already been defined error" But I don't know how to rly solve this as I need to have functions referring to other specializations

I am using Visual Studio Community 2019 version 16.11.6


Solution

  • An explicit specialization is a distinct class and does not have to resemble the original template at all. You can change the functions, make completely different ones, or whatever.

    This is usually the point of partial specialization, so a const T can be a different interface than a plan T etc.

    Any explicit specializations must be declared before that specialization is used. That's why you get redeclaration errors.

    Also, you showed <float> twice, I assume that's a paste error? The one in Double.h should be <double> right?

    You violated that with your circular reference. You can fix that by declaring the one you need (without defining it), similarly to how you do with mutually recursive functions.

    Here is the correctly-compiling and running code: https://godbolt.org/z/x1TcTE7Me

    You'll notice that the definition of

    //template<>      // Don't use the `template<>` prefix here!!!
    inline void Something<float>::SayDouble(Something<double> p_D) {
            std::cout << p_D.Name << '\n';
        }
    // I'm showing it with `inline` in case you put it in a header.  It can go in
    // some CPP file though, as it's been declared in the class specialization.
    

    does not use the template prefix. That's because this is defining a member function (that's not a template) for a class just like a normal class — the explicit (and not partial) specialization is a normal class like any other, not a template. It just says "when I ask for this specialization of that template, use this class instead of generating one".

    Finally, the parameter name _D is not allowed. "If the programmer uses such identifiers, the behavior is undefined."