Minimal implementation:
#include <array>
#include <iostream>
template <typename T>
auto universal_ref(T&& arr)
{
for (auto && v : arr)
std::cout << v << '\n';
}
template <typename T, size_t N>
auto not_universal_ref(std::array<T, N>&& arr)
{
for (auto && v : arr)
std::cout << v << '\n';
}
Question: which strategy could be used to transform it into an universal reference while still ensuring the argument must be an array?
You can require that T
is some std::array<U,N>
via std::enable_if
:
template <typename T> struct is_array : std::false_type {};
template <typename U,std::size_t N> struct is_array<std::array<U,N>> : std::true_type {};
template <typename T>
std::enable_if_t<is_array<std::decay_t<T>>::value> universal_ref(T&& arr)
{
for (auto && v : arr)
std::cout << v << '\n';
}
Afaik nothing in the language specifies what a forwarding reference is. It is merely template argument deduction and reference collapsing rules which govern how T
is deduced when you call universal_ref
. Hence, std::array<T,N>&&
in your other example is not a forwarding reference, the type of the reference is not deduced nor is reference collapsing applied, it is simply a rvalue reference.