了解std :: forward

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.它需要搜索所有类型以找到匹配并能够以某种方式消除冲突的歧义.这是不合理的,所以标准不允许这样做.


Bar*_*rry 8

您必须为设计指定类型的原因forwarda函数内部会发生什么:

template<typename T,typename Arg>
T* factory( Arg&& a )
{
    // 'a' is always an lvalue here
Run Code Online (Sandbox Code Playgroud)

由于a始终左值,没有足够的信息a本身能够确定它是否是通过作为一个左或右值.信息仅可通过类型获得,该类型Arg将为XX&.没有那些额外的类型信息,就不可能知道现在是否a必须作为左值或左值转发......这就是你需要提供它的原因:

    return new T(std::forward<Arg>(a));
}
Run Code Online (Sandbox Code Playgroud)

  • 好吧,我认为OP问了一个稍微不同的问题.无论如何都会留在这里. (4认同)