c++templatestemplate-specializationmember-variables

How do member variables work with specialized class templates?


I'm trying to write a very simple specialized class template that has a member variable and can print that member variable differently in specialized situations. I know the example is pretty useless, but it illustrates the question pretty well.

When specializing class templates it seems that the specializations of the class don't share the same member variables, so the following code won't compile...

#include <iostream>
#include <string>

// Class template
template <typename T>
struct S
{
    S(const T& t)
        : t(t)
    {}

    void print()
    {
        std::cout << t << std::endl;
    }
private:
    T t;
};

// Specialization
template <>
struct S<std::string>
{
    void print()
    {
        // ERROR: "t" is not defined in this context
        std::cout << "string: " << t << std::endl;
    }
};

This suggests that I would need to write a separate constructor for every specialization and have a separate member variable t for each specialization which feels like it would quickly become a lot of duplicated code and effort if I have many specializations.

If what I am saying is true, then is it bad practice to use member variables in specialized class templates altogether? Are there any alternatives that result in less code duplication?


Solution

  • Please also look at @0x499602D2's answer, it is simpler and works for many practical cases.

    You are correct, the specializations are basically totally independet from each other and the original template, so you would have to write everything new. A way to get around that would be to use inheritance.

    #include <iostream>
    #include <string>
    
    // Class template
    template <typename T>
    struct Base
    {
        Base(const T& t)
            : t(t)
        {}
    
        virtual void print()
        {
            std::cout << t << std::endl;
        }
    
    protected:
        T t;
    };
    
    template<class T>
    struct S: Base<T> {
    };
    
    // Specialization
    template <>
    struct S<std::string>: Base<std::string>
    {
        void print() override
        {
            std::cout << "string: " << t << std::endl;
        }
    };