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)
CodePudding user response:
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');
}
CodePudding user response:
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');
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
.