user6000117
user6000117

Reputation: 43

Is it possible to perfect forward a template template parameter

I know how to perfect forward a parameter. However, I read from different sources (e.g. Effective Modern C++ Item 24 - Scott Meyers) that one can only perfect-forward when you have the exact template name, e.g.:

template<typename T>
void foo(T&& param) { bar(std::forward<T>(param)); }

What I am looking for is if there is a way to perfect forward an template template parameter, e.g.:

template<template<int, class TypeT> class Vector, int Size, typename TypeT>
void foo(Vector<Size, TypeT>&& param) { bar(std::forward<Vector<Size, TypeT>>(param)); }

When I compile the above, I get an error message: "You cannot bind an lvalue to an rvalue reference" (VC12), which suggest to me that the compiler does not recognize the && as a "universal reference" but as an rvalue reference. This perfect fowarding could be useful to me because I can take advantage of the deduced TypeT and Size.

The question: is it possible to perfect forward template template parameters? If so, where is my syntax incorrect?

Thanks!

Upvotes: 4

Views: 1146

Answers (1)

T.C.
T.C.

Reputation: 137315

A "universal reference" (the standard term is forwarding reference) is (by definition) an rvalue reference to a cv-unqualified template parameter, i.e., T&&.

Vector<Size, TypeT>&& is an rvalue reference, not a forwarding reference.

If you want to get the value of the template arguments, write a trait:

template<class> struct vector_traits;

template<template<int, class TypeT> class Vector, int Size, typename TypeT>
struct vector_traits<Vector<Size, TypeT>>{
    static constexpr int size = Size;
    using value_type = TypeT;
};

And inspect std::decay_t<T>:

template<class T>
void foo(T&& t) {
    using TypeT = typename vector_traits<std::decay_t<T>>::value_type;
    // use TypeT.
}

You can also move it to a default template argument, which makes foo SFINAE-friendly (it's removed from the overload set if std::decay_t<T> isn't a "vector"):

template<class T,
         class TypeT = typename vector_traits<std::decay_t<T>>::value_type>
void foo(T&& t) {
    // use TypeT.
}

Upvotes: 5

Related Questions