Search code examples
c++sfinaec++-conceptsforwarding-reference

Forward reference vs rvalue


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?


Solution

  • 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';
    }
    

    Live Demo

    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.