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.
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.