Pao*_*o M 9 c++ perfect-forwarding c++11
为什么编译器无法推导出模板参数std::forward
?
我的意思是:
#include <memory>
#include <iostream>
struct X{};
struct A{
A( const X& ) { std::cout << "cpy ctor\n"; }
A( X&& ) { std::cout << "move ctor\n"; }
};
X foo() { return {}; }
template<typename T,typename Arg>
T* factory( Arg&& a )
{
return new T(std::forward(a));
// ----------^^^^^^^^^^^^^^^ error: can't deduce template parameter
}
int main()
{
factory<A>(foo());
}
Run Code Online (Sandbox Code Playgroud)
我知道这是一个设计选择(由于std::remove_reference
在定义中std::forward
),以避免用户忘记指定类型.我不能得到的是:为什么它的实施方式可以防止扣除?为什么编译器不只是将forward
模板参数推断为Arg
.
Tar*_*ama 12
std::forward
声明如下:
template< class T >
T&& forward( typename std::remove_reference<T>::type& t );
Run Code Online (Sandbox Code Playgroud)
typename std::remove_reference<T>::type
是一个非推断的上下文.编译器无法知道T
应该推导出哪个,因为它不理解type
成员类型和给定类型之间的语义连接T
.它需要搜索所有类型以找到匹配并能够以某种方式消除冲突的歧义.这是不合理的,所以标准不允许这样做.
您必须为设计指定类型的原因forward
是a
函数内部会发生什么:
template<typename T,typename Arg>
T* factory( Arg&& a )
{
// 'a' is always an lvalue here
Run Code Online (Sandbox Code Playgroud)
由于a
是始终左值,没有足够的信息a
本身能够确定它是否是通过作为一个左或右值.该信息仅可通过类型获得,该类型Arg
将为X
或X&
.没有那些额外的类型信息,就不可能知道现在是否a
必须作为左值或左值转发......这就是你需要提供它的原因:
return new T(std::forward<Arg>(a));
}
Run Code Online (Sandbox Code Playgroud)