Search code examples
c++c++11template-templatestemplate-functionforwarding-reference

Forwarding references and template templates


Consider these two template functions:

template<typename T>
void foo(T&& bar) {
    // do stuff with bar, which may or may not be an instance of a templated class
}

template<typename U, template<typename> class T>
void foo(T<U>&& bar) {
    // do stuff with bar, which must be an instance of a templated class
}

Why does the former accept lvalues (by using a forwarding reference) while the latter does not?


It looks like Can an identity alias template be a forwarding reference? may be related to this as well, but it seems to cover a different facet of the restrictions on forwarding references.


Solution

  • Because that's how the standard says the language should work.

    [14.8.2.1][temp.deduct.call]
    3.If P is a cv-qualified type, the top level cv-qualifiers of P’s type are ignored for type deduction. If P is a reference type, the type referred to by P is used for type deduction. A forwarding reference is an rvalue reference to a cv-unqualified template parameter. If P is a forwarding reference and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction.

    Only an rvalue-reference to a CV-unqualified template parameter can be deduced as an l-value reference in this manner.

    To achieve what you are trying to do, you might be able to use a trait to extract the template template parameter.

    #include <type_traits>
    
    /***
     * Extract template from template type.
     */
    template <typename I> struct get_template;
    
    template <template<class> typename T, typename C>
    struct get_template<T<C>> {
      template <typename U>
      using temp = T<U>;
    };
    
    
    
    
    
    template <typename T> struct A{};
    
    struct B;
    
    template<typename W>
    void foo(W && bar) {
      typedef typename get_template<typename std::remove_reference<W>::type>::template temp<int> new_type;
      new_type my_variable;
    }
    
    int main() {
      A<B> temp;
      foo(temp);
    }
    

    Or, just overload the function for const & and && as usual.