转发引用和模板模板
Forwarding references and template templates
考虑这两个模板函数:
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
}
为什么前者接受左值(通过使用转发引用)而后者不接受?
看起来 也可能与此有关,但它似乎涵盖了转发引用限制的不同方面。
因为这就是标准所说的语言应该工作的方式。
[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.
只有对 CV 非限定模板参数的右值引用才能以这种方式推断为左值引用。
要实现您正在尝试做的事情,您可以使用特征来提取模板模板参数。
#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);
}
或者,像往常一样重载 const & 和 && 的函数。
如果你想保留一个转发引用参数,同时推导一个参数的类型,你可以使用下面的解决方案:
#include <type_traits>
#include <utility>
template <typename T>
struct tag {};
template <typename T, typename U, template <typename> class C>
void foo(T&& t, tag<C<U>>)
{
}
template <typename T>
auto foo(T&& t)
-> decltype(foo(std::forward<T>(t), tag<typename std::decay<T>::type>{}))
{
return foo(std::forward<T>(t), tag<typename std::decay<T>::type>{});
}
考虑这两个模板函数:
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
}
为什么前者接受左值(通过使用转发引用)而后者不接受?
看起来
因为这就是标准所说的语言应该工作的方式。
[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.
只有对 CV 非限定模板参数的右值引用才能以这种方式推断为左值引用。
要实现您正在尝试做的事情,您可以使用特征来提取模板模板参数。
#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);
}
或者,像往常一样重载 const & 和 && 的函数。
如果你想保留一个转发引用参数,同时推导一个参数的类型,你可以使用下面的解决方案:
#include <type_traits>
#include <utility>
template <typename T>
struct tag {};
template <typename T, typename U, template <typename> class C>
void foo(T&& t, tag<C<U>>)
{
}
template <typename T>
auto foo(T&& t)
-> decltype(foo(std::forward<T>(t), tag<typename std::decay<T>::type>{}))
{
return foo(std::forward<T>(t), tag<typename std::decay<T>::type>{});
}