template <class D, class...>
struct return_type_helper
{
using type = D;
};
template <class... Types>
struct return_type_helper<void, Types...> : std::common_type<Types...>
{
static_assert(
// why can't I use reference wrappers?
std::conjunction_v<not_ref_wrapper<Types>...>,
"Types cannot contain reference_wrappers when D is void"
);
};
template <class D = void, class... Types>
constexpr std::array<typename return_type_helper<D, Types...>::type, sizeof...(Types)> make_array(Types&&... t)
{
return {std::forward<Types>(t)...};
}
void foo()
{
int x = 7355608;
auto arr = make_array(std::ref(x)); // does not compile
}
Why does std::experimental::make_array()
have a static_assert()
that disallows use of std::reference_wrapper
when the type of the array is automatically deduced? Creating an array of reference wrappers is otherwise perfectly legal, that is the compiler has no problem with
auto arr2 = std::array<decltype(std::ref(x)),1>{std::ref(x)};
CodePudding user response:
Checking the proposal N3824 confirms my initial suspicion.
Namely, the static_assert
check was added to explicitly disallow type deduction of a std::array<std::reference_wrapper<T>, N>
from make_array
, because the proposal’s author has deemed this usage error-prone.1
That is, with the following code:
auto x = 42;
auto a = make_array(std::ref(x));
users could reasonably expect the type of a
to be std::array<int&, 1>
, because std::ref
behaves similarly in other contexts.
In reality std::array<int&, 1>
does not name a valid type and cannot be constructed, so the danger of this confusion is minimal. Still, the author found it worth erring on the side of caution here, and making the API maximally defensive.
Consequently, if the user wants to create an array of reference wrappers, they need to explicitly request that type:
auto a = make_array<std::reference_wrapper<int>>(std::ref(x));
1 Here’s the proposal’s wording:
Ban
reference_wrapper
in themake_tuple
-like interface.make_tuple
andmake_pair
have special handling ofreference_wrapper
, then user might expect that the expressionmake_array(ref(a), ref(b))
also results in a tuple-like object storing
T&
.