Reputation: 43
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
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