C++完美转发: why do we need forward() if we can use 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 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 的有点棘手的解决方案?

最佳答案

你的解决方案真的,真的很糟糕。

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

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

In this way, we don't have to write multiple functions and we are able to efficiently deal with both lvalues and rvalues.

你和他们打交道,但你做错了。如果使用右值调用包装器,它会将它们“转发”为左值。如果 func 关心左值和右值之间的区别(如果不关心,为什么还要使用完美转发呢?)如果 func 关心 const 和非常量参数之间的区别。

关于C++完美转发: why do we need forward() if we can use const_cast()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28498769/

相关文章:

c++ - 没有可用的复制构造函数或声明了复制构造函数 'explicit'

c++ - 随机删除 Excel 工作表失败

c++ - cppreference 使用术语 "[Object' s] 身份”对于 c++11 和 c++17 是否有两种不同的含义?

c++ - 标签分发中的转发参数

使用 Visual Studio 的 C++ 编译错误(LNK1120 和 LNK2019)

c++ - Boost::ini_parser:读取特定部分值的方法是什么?

c++ - 原始数组是否比 std::array 有任何优势?

c++ - Windows 线程(c 运行时、pthreads、std::thread)

c++ - 如何将 vector 中的可变参数转换为它是参数的持有者?

c++ - 使用 std::forward 的主要目的是什么以及它解决了哪些问题?