Reputation: 11000
I have the following example:
#include <array>
struct A {
const char* str;
const char* str2;
};
template<size_t N>
struct As {
std::array<A,N> elems_;
};
template<class... Args>
As(Args...)->As<sizeof...(Args)>; //<-- NOTE: deduction guide !
constexpr static As as{A{"a","b"}, A{"1","2"}};//<-- 'retyping' A here
int main() {
return as.elems_.size();
}
While this codes works, I would like to avoid the 'retyping' of A
's inside the aggregate list, but if I leave it out the deduction guide fails with: "cannot deduce template arguments for 'As'"
(which, I guess makes sense). Maybe one way to fix this would be by hand-writing whatever number of deduction guides i need since then I could write the A
type in each deduction guide (that is: one deduction for each size I need of the container).
Upvotes: 4
Views: 188
Reputation: 23701
Nested aggregate initialization has the more or less surprising behavior that you don't add nested {
/}
to match.
For example, this is how you initialize std::array<std::array<int, 2>, 2>
:
std::array<std::array<int, 2>, 2> arr = { 1, 1, 2, 2 };
Doing { {1, 1}, {2, 2} }
does not work!
Similarly, aggregate initialization in your case would require no nested {
/}
with CTAD already done (well, the template parameter given):
constexpr static As<2> as{"a","b", "1","2"}; // Ok!
Knowing that, we can just add the following deduction guide:
template<class ... Ts>
As(Ts...) -> As<(sizeof...(Ts) + 1)/2>;
This chooses N
as "half the number of arguments". And indeed, now you can initialize like this:
constexpr static As as{"a","b", "1","2"}; // Deduces N = 2.
Demo: https://godbolt.org/z/oznEwl
Yes, this loses the ability to structure the input with {
/}
for better readability, but I blame aggregate initialization here (see nested array example above).
Upvotes: 5