Search code examples
c++templatestemplate-specializationfunction-definition

C++ Define member functions for all template specialized classes


I have a templated class foo<T> which is specialized in many different ways.
Some of which have a lot of common code that relies on specialized functions.

For example, consider the following:

#include <iostream>

template <class T>
struct foo;

template <class T>
struct foo<T*> {
    void different_function() const { std::cout << "calling from T*\n"; }
    void same_function() const;
};

template <class T>
struct foo<T&> {
    void different_function() const { std::cout << "calling from T&\n"; }
    void same_function() const;
};

template <class T>
void foo<T>::same_function() const { // this yields an error
    std::cout << "the exact same function but now ";
    different_function();
}

int main() {
    foo<int*> a;
    a.different_function();
    a.same_function();
    foo<int&> b;
    b.different_function();
    b.same_function();
}

Each specialization of foo<T>::different_function() is uniquely specified, and I want foo<T>::same_function() to have generally the same code structure but is reliant on the specialization of different_function().

I have tried:

  • adding the methods to the default foo type, but that only defines the code for the default foo.
  • using a base class for all the common methods, but that won't work since the different_function from the foo class is required.

How could I solve this issue?


Solution

  • In C++23 you can use a templated explicit this parameter in same_function in the base class:

    struct CommonBase
    {
        // equivalent to:
        // template <typename T> void same_function(this const T &self)
        void same_function(this const auto &self)
        {
            std::cout << "the exact same function but now ";
            self.different_function();
        }
    };
    

    Pre-C++23 you can use CRTP:

    template <typename T>
    struct CommonBase
    {
        void same_function() const
        {
            std::cout << "the exact same function but now ";
            static_cast<const T &>(*this).different_function();
        }
    };
    

    (Then inherit like this: struct foo<T*> : CommonBase<foo<T*>>.)

    Or you can avoid specializations in the first place, and just use if constexpr and requires (or std::enable_if_t before C++20) to alter the behavior and to disable certain functions respectively.