c++variadic-templatestemplate-specializationdefault-parametersnon-type

Default value for template parameter, followed by non-type parameter pack


I'm struggling to make this code work

template <typename T, typename U = int, auto... Params>
class Foo {};

int main()
{
    auto foo1 = Foo<int, int, 1, 2, 3>{};
    auto foo2 = Foo<int, 1, 2, 3>{}; // I want it to compile
}

It looks like I need some hack. I tried partial specialization, but it doesn't work either

template <typename T, typename U, auto... Params>
class Foo {};

template <typename T, auto... Params>
class Foo<T, int, Params...> {};

int main()
{
    auto foo1 = Foo<int, int, 1, 2, 3>{};
    auto foo2 = Foo<int, 1, 2, 3>{}; // I want it to compile
}

I can't find anything closely related to this, help pls :)


Solution

  • Unfortunately due to the way that template deduction works, this is ...not going to work.

    Here's one alternative approach where the first template parameter is always a tuple, with one or two types, with the second type defaulting to an int:

    #include <tuple>
    
    template<typename T, auto ...Params> class Foo;
    
    template<typename T, typename U, auto ...Params>
    class Foo< std::tuple<T, U>, Params...> {
    
        // Your template goes here, making use of T and U
    };
    
    template<typename T, auto ...Params>
    class Foo< std::tuple<T>, Params...> : Foo<std::tuple<T, int>, Params...> {
    
        // Might need to define some cleanups here, like a delegating constructor,
        // and/or delegated overload operators.
    
    };
    
    Foo<std::tuple<char>, 3, 4> defaulted;
    
    Foo<std::tuple<char, float>, 3, 4> non_defaulted;
    

    With a little bit more elbow grease it should be possible to require a formal std::tuple only when the 2nd optional type needs to be specified, and just specify the primary type directly (although that will create some avoidable confusion if the primary type is a std::tuple, itself).