简体   繁体   中英

variadic template deduction with two template argument fails

When I have the class:

template <std::same_as<char> ... Indices>
struct MIndices {
        std::tuple<Indices...> indices;
        MIndices() = delete;
        constexpr explicit MIndices(Indices... args) : indices(args...) {
        }
};

The following call works:

    MIndices myI('i', 'j', 'l', 'z');

But changing the template to the following:

template <size_t Dims, std::same_as<char> ... Indices>
struct MIndices {
        std::tuple<Indices...> indices;
        MIndices() = delete;
        constexpr explicit MIndices(Indices... args) : indices(args...) {
        }
};

And then calling it with

    MIndices<4> myI('i', 'j', 'l', 'z');

suddenly fails to deduce the arguments.

Why and how can I fix this?

So in principle I would just like to have a compile-time way to specify the number of tuple arguments. If this is a bad way for doing it please tell me.

I am using c++20. (gcc-12.1)

Why and how can I fix this?

The problem is that when using class template argument deduction(aka CTAD), all template parameters must be determined by the deduction process or from default arguments. It is not possible to explicitly specify a few arguments and deduce others .

So to solve this you have to either explicitly specify all the template arguments or let all of them be deduced. So one way to fix this is:

MIndices<4, char, char, char, char> myI('i', 'j', 'l', 'z');

Working demo


Perhaps an more simplified example might help illustrate this:

template<typename T1, typename T2, typename T3>
class Custom
{
    public:
    
        Custom (T1 x, T2 y, T3 z)
        {

        }
};
int main()
{
    std::string s;
    Custom c(3, 2.343, s); //works 

    //Custom<int> b(4, 2,343, s); //WON'T WORK

    Custom<int, int, std::string> k(4, 4, "s"); //works
}

If this is a bad way for doing it please tell me.

You have the option of using sizeof...(Indices) so there doesn't seem to need to have an extra nontype template parameter of type size_t .

If Dims should equal the number of parameters passed, you should use the sizeof... operator instead of letting the caller specify the size.


CTAD (class template argument deduction) only works when all template arguments of the class are deduced.

The workaround is to let all arguments be deduced. You can wrap the class that deduces the indices into another one that can have the size given explicitly:

#include <iostream>
#include <tuple>

template <size_t Dims>
struct wrapper {
    template <std::same_as<char> ... Indices>
    struct MIndices {
        std::tuple<Indices...> indices;
        MIndices() = delete;
        constexpr explicit MIndices(Indices... args) : indices(args...) {
        }
    };
};
    
int main() {
   wrapper<4>::MIndices myI('i', 'j', 'l', 'z');
}

Live Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM