Search code examples
c++templatesc++20c++-conceptsmember-functions

How can you enable a class template member function only if a template argument was provided?


Is it possible to have a class with an optional template parameter that can be called like this?:

#include <iostream>

template <typename T = void>
class A final
{
public:
    // This class can be called only when T exists.
    void f()
    {
        printf("%d\n", member);
    }

    // This method can be called only when T is missing.
    void g()
    {
        printf("No template parameter\n");
    }
public:
    T member;
};

int main()
{

    A<int> a1;
    A a2;
    a1.f(); // should be valid
    a1.g(); // should be invalid, cannot compile
    a2.f(); // should be invalid, cannot compile
    a2.g(); // should be valid

    return 0;
}

If yes, what are the std functions that should be used?


Solution

  • You might use the "old" way with specialization:

    template <typename T = void>
    class A final // generic case, T != void
    {
    public:
        void f() { std::cout << member << std::endl; }
    
    public:
        T member;
    };
    
    template <>
    class A<void> final
    {
    public:
        void g() { printf("No template parameter\n"); } // actually `void` and not "No".
    };
    

    By turning your class into variadic, to handle absent parameter as empty pack, instead of void, you might do:

    template <typename... Ts>
    class A final
    {
    static_assert(sizeof...(Ts) < 2);
    public:
        void f() requires (sizeof...(Ts) == 1) { std::cout << std::get<0>(member) << std::endl; }
        void g() requires (sizeof...(Ts) == 0) { printf("No template parameter\n"); }
    
    public:
        std::tuple<Ts...> member;
    };