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

时间:2015-02-13 11:39:45

标签: 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 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); }

以下是该问题的经典解决方案:

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);
}

但为什么我们不能将const_cast用于此目的?我们可以这样写:

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);
}

通过这种方式,我们不必编写多个函数,我们能够有效地处理左值和右值。那么为什么我们真的需要一个有点棘手的解决方案,使用参考折叠,模板参数推导和std::forward

1 个答案:

答案 0 :(得分:9)

你的解决方案真的,真的坏。

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

基本上你的包装器完全改变了参数,总是调用func的相同重载,而不考虑原始参数的const限定符和值类别。

  

通过这种方式,我们不必编写多个函数,我们能够有效地处理左值和右值。

你处理它们,但你做错了。如果用rvalues调用你的包装器,它就会转发&#34;转发&#34;他们作为左值。如果func关心左值和右值之间的区别(如果它没有,为什么还要使用完美的转发?),如果func关心的话,那么你的程序就会行为不端。 const和非const参数之间的区别。