Very often in C++ I want an STL container of a type which has a reference member:
struct C {};
struct S
{
S() = default;
S(const C& c) : _c(c)
{}
const C& _c; // I always have to use a pointer here
};
int main()
{
C c;
std::array<S, 10> arr{ c }; // Can c be passed here?
return 0;
}
However, because references have to be set from the beginning, I can never get this to work and have to use a pointer (which I really dislike).
The above doesn't compile.
error: no matching constructor for initialization of 'S'
Is it possible to pass the reference in via the std::array
's constructor and avoid using a pointer?
Is it possible to pass the reference in via the
std::array
's constructor and avoid using a pointer?[...] keep repeating
c
, how to fill out all1000
elements is the elegant solution?
If you do not like the pointers, I would suggest using the std::reference_wrapper
instead of plane references. Why:
What is the difference between std::reference_wrapper and a simple pointer?
Benefits of using reference_wrapper instead of raw pointer in containers?
#include <functional> // std::reference_wrapper
struct S
{
constexpr explicit S(C& c)
: _c{c} {}
private:
std::reference_wrapper<C> _c;
};
Now, to fill the array, (in C++20) you could write a helper make_ref_array()
as follows:
template <size_t N>
constexpr auto make_ref_array(C& refArg)
{
return [&refArg]<size_t... Is>(std::index_sequence<Is...>) {
return std::array<S, sizeof...(Is)>{(static_cast<void>(Is), S{ refArg })...};
}(std::make_index_sequence<N>{});
}
so that, the array creation be like
C c;
auto arr = make_ref_array<100u>(c);
Now, it can be more generic as:
template <typename T, size_t N, typename... Args>
constexpr auto make_ref_array(Args&... args)
{
return []<size_t... Is, typename... Ts>(std::index_sequence<Is...>, Ts&... ts) {
return std::array<T, sizeof...(Is)>{(static_cast<void>(Is), T{ ts... })...};
}(std::make_index_sequence<N>{}, args...);
}
Note that, all the args
will be referenced to construct the T
, even if the other data members are not references.
For the compilers older than C++20, the template lambda must be moved to a separate template function as like in this example