Disclaimer: I'm not sure if this fails any other requirements on specializations in std::
but it should deal with the aggregate requirement on std::array
.
A specialization of std::array
for foo
(or template <class T> class dyn_var
that you mentioned later) would have to be be an aggregate, so you can't add a constructor.
However, aggregates of aggregates don't require extra braces when initializing them due to brace elision. Consider:
template<class T, std::size_t N>
struct array {
struct inner_array {
T data[N];
};
inner_array m_data;
};
array<int, 3> var{1, 2, 3}; // initializes data in m_data
I think this opens up for a specialization that fulfills the aggregate requirement. Here's my version of dyn_var<T>
:
namespace builder {
struct cheap_tag_t {} cheap_tag;
template <class T>
class dyn_var {
public:
dyn_var() { std::cout << "expensive ctor\n"; }
dyn_var(T) { std::cout << "T ctor\n"; }
dyn_var(cheap_tag_t) { std::cout << "cheap ctor\n"; }
};
} // namespace builder
And one possible std::array
specialization that uses the cheap constructor:
template <class T, std::size_t N>
requires (N != 0)
struct std::array<builder::dyn_var<T>, N> {
struct inner_array {
builder::dyn_var<T> data[N];
};
inner_array m_data{
[]<std::size_t... I>(std::index_sequence<I...>){
// RVO:
return inner_array{((void)I, builder::cheap_tag)...};
}(std::make_index_sequence<N>())
};
// ... member functions ...
};
Now these would both use the cheap constructor:
std::array<builder::dyn_var<int>, 10> foos1;
std::array<builder::dyn_var<int>, 10> foos2{};
while this would use the T ctor
for the first 5 elements and the expensive constructor for the remaining elements:
std::array<builder::dyn_var<int>, 10> foos3{1,2,3,4,5};
The last point, that only partially initializing the std::array
triggers the default construction of the rest of the elements may be a show stopper since it will certainly confuse the end users, but I thought this may be worth considering nevertheless.
Demo