C++完美转发:如果我们可以使用CONTYSCAST(),为什么需要转发?

C++完美转发:如果我们可以使用CONTYSCAST(),为什么需要转发?,c++,c++11,perfect-forwarding,const-cast,C++,C++11,Perfect Forwarding,Const Cast,对于完美转发问题的常见描述是,我们最好不要将&和const&的组合用作包装函数参数,因为在这种情况下,我们必须编写多个函数,涵盖函数参数的所有组合: template <typename T1, typename T2> void wrapper(T1& e1, T2& e2) { func(e1, e2); } template <typename T1, typename T2> void wrapper(const T

对于完美转发问题的常见描述是,我们最好不要将&和const&的组合用作包装函数参数,因为在这种情况下,我们必须编写多个函数,涵盖函数参数的所有组合:

template <typename T1, typename T2>
void wrapper(T1& e1, T2& e2)                { func(e1, e2); }

template <typename T1, typename T2>
void wrapper(const T1& e1, T2& e2)          { func(e1, e2); }

template <typename T1, typename T2>
void wrapper(T1& e1, const T2& e2)          { func(e1, e2); }

template <typename T1, typename T2>
void wrapper(const T1& e1, const T2& e2)    { func(e1, e2); }
这样,我们就不必编写多个函数,并且能够有效地处理左值和右值。那么,为什么我们真的需要一个使用引用折叠、模板参数推断和std::forward的有点棘手的解决方案呢?

您的解决方案真的非常糟糕

您修改了参数的常量,并且不保留参数的值类别,即左值或右值

基本上,您的包装器完全改变了参数,并且始终调用相同的func重载,而不考虑原始参数的常量限定符和值类别

这样,我们就不必编写多个函数,并且能够有效地处理左值和右值

你和他们打交道,但你做错了。如果用右值调用包装器,它会将它们作为左值转发。如果func关心左值和右值之间的区别,那么您的程序就会出现错误,如果它不关心,为什么还要麻烦使用完美转发呢?如果func关心常量参数和非常量参数之间的区别,它也会表现不好。

您的解决方案非常非常糟糕

您修改了参数的常量,并且不保留参数的值类别,即左值或右值

基本上,您的包装器完全改变了参数,并且始终调用相同的func重载,而不考虑原始参数的常量限定符和值类别

这样,我们就不必编写多个函数,并且能够有效地处理左值和右值


你和他们打交道,但你做错了。如果用右值调用包装器,它会将它们作为左值转发。如果func关心左值和右值之间的区别,那么您的程序就会出现错误,如果它不关心,为什么还要麻烦使用完美转发呢?如果func关心常量参数和非常量参数之间的区别,它也会表现不好。

如果func重载,并且根据其参数是否为常量执行不同的操作,该怎么办?事实上,如果func不根据其参数的常量和值类别做不同的事情,为什么还要用完美转发来调用它呢?如果有人真的传递了一个声明为常量的对象呢?而且,您的解决方案不保留参数的值类别,即它不将右值作为右值转发,一切都变成了非常量左值。。。这是我见过的最不完美的转发。这可能被称为糟糕的转发。可能重复的是,你基本上是在问完美转发的用途是什么?隐藏在一层薄纱后面,如果我不想使用完美转发,我可以做完全不同的事情如果func重载,并且根据其参数是否为const执行不同的操作,该怎么办?事实上,如果func不根据其参数的常量和值类别做不同的事情,为什么还要用完美转发来调用它呢?如果有人真的传递了一个声明为常量的对象呢?而且,您的解决方案不保留参数的值类别,即它不将右值作为右值转发,一切都变成了非常量左值。。。这是我见过的最不完美的转发。这可能被称为糟糕的转发。可能重复的是,你基本上是在问完美转发的用途是什么?隐藏在一层薄纱后面,如果我不想使用完美转发,我可以做完全不同的事情
template <typename T1, typename T2>
void wrapper(T1&& e1, T2&& e2) {
    func(forward<T1>(e1), forward<T2>(e2));
}

template<class T>
T&& forward(typename std::remove_reference<T>::type& t) noexcept {
    return static_cast<T&&>(t);
}
template <typename T1, typename T2>
void wrapper(const T1& e1, const T2& e2)    
{ 
    T1& e1_ref = const_cast<T1&>(e1);
    T2& e2_ref = const_cast<T2&>(e2);
    func(e1_ref, e2_ref);
}