I have the following peace of example code:
#include <array>
template<std::size_t N>
struct Cfg {
std::array<int, N> Values;
// ... more fields
}
constexpr Cfg c = {
.Values = { 0, 1, 2, 3 }
};
Is it possible to deduce the template parameter N from the designated initializers? Using makeArray or initialize it with a defined array doesn't work either. Doing Cfg<4> for example works.
CodePudding user response:
The designated initializer is not relevant here. For the purpose of class template argument deduction it is just handled as if it was a usual element of the initializer list.
(At least that is how I read the standard. It is a bit unclear in [over.match.class.deduct] how a designated initializer ought to be handled when actually performing the overload resolution over the set of deduction guides.)
The problem is that there is no implicit deduction guide to deduce from the nested (untyped) braces, which can only deduce std::initializer_list
and (reference to) array types, but your member is std::array
. Or to be more precise the implicit aggregate deduction guide will not be formed under these circumstances.
Both
constexpr Cfg c = {
.Values = { 0, 1, 2, 3 }
};
and
constexpr Cfg c = {
{ 0, 1, 2, 3 }
};
will fail, but both
constexpr Cfg c = {
.Values = std::array{ 0, 1, 2, 3 }
};
and
constexpr Cfg c = {
std::array{ 0, 1, 2, 3 }
};
will work since you now gave the initializer a type that the implicit aggregate deduction guide (since C 20) can deduce against the std::array
member.
To make the syntax without explicit std::array
work you will need to add a deduction guide that can deduce the size of the nested braced-init list, for example:
template<typename T, std::size_t N>
Cfg(const T(&)[N]) -> Cfg<N>;
MSVC and Clang do not accept this though, I am not sure why.
CodePudding user response:
This is possible with C 17's class template argument deduction:
#include <array>
template<std::size_t N>
struct Cfg {
std::array<int, N> Values;
};
constexpr Cfg c {
.Values = std::array { 0, 1, 2, 3 }
};