如何完美转发一个常量引用或可移动右值的通用引用?

Leo*_*eon -1 c++ copy-constructor rvalue-reference move-constructor perfect-forwarding

我用 C++20 编写了一个无锁且线程安全的环形队列,到目前为止它可以工作。唯一不完美的是它必须有两个enque()方法,一个接受对左值的 const 引用作为参数,另一个接受对右值的引用,以便将右值移入队列而不是再次构造。

\n

之前版本的代码如下,只是一个骨架,进行简化:

\n
template <typename T>\nclass RingQue_t {\npublic:\n    explicit RingQue_t( size_t capacity );\n    ~RingQue_t();\n    bool deque( T& dest_ ) { return true; };\n\n    // If we offer a const ref, the compiler will select this one\n    bool enque( const T& src_ ) {\n        // a lot of same codes goes here for a same logic...\n\n        new( _buff + _tail ) T( src_ );\n    };\n\n    // If we offer a rvalue ref, the compiler will select this one\n    bool enque( T& src_ ) {\n        // a lot of same codes goes here for a same logic...\n\n        new( _buff + _tail ) T( std::move( src_ ) );\n    };\n\nprotected:\n    T*  _buff = nullptr;\n};\n
Run Code Online (Sandbox Code Playgroud)\n

我正在尝试将这两种方法合并为一种,并阅读了一些有关的文档和示例std::forward,但我仍然无法正确使用它。\n这是我的期望:

\n
template <typename T>\nclass RingQue_t {\npublic:\n    template<typename U>\n    bool enque( U&& src_ ) {\n        // new( _buff + _tail ) T( src_ );\n        // new( _buff + _tail ) T( std::move( src_ ) );\n        // new( _buff + _tail ) T( std::forward<T>( src_ ) );\n\n        std::allocator<T> allc;\n        allc.construct( _buff + _tail, std::forward<T>( src_ ) );\n        return true;\n    };\n};\n\n// testing\nconst std::string s0 { "s0" };\nRingQue_t<std::string> str_que( 16 );\nstr_que.enque( std::string { "s1" } ); // works\nstr_que.enque( s0 ); // can not pass the compiling.\n
Run Code Online (Sandbox Code Playgroud)\n

评论里的所有解决方案都试过了,没有一个有效。我总是收到错误消息:

\n
\n

类型 \xe2\x80\x98std::remove_referencestd::__cxx11::basic_string<char >::type&\xe2\x80\x99 {aka \xe2\x80\x98std::__cxx11::basic_string&\xe2\x80\ 的绑定引用x99} 到 \xe2\x80\x98const std::__cxx11::basic_string\xe2\x80\x99 丢弃限定符

\n
\n

正确的使用方法是什么std::forward

\n

Cos*_*kel 6

这个问题与事实有关,enque()没有正确地表达论证的恒定性。这是因为U被推导为const T&,但在使用std::forward<T>()此常量转发后会丢失。为了解决这个问题,只需替换std::forward<T>()std::forward<U>()

另请注意,std::allocator<T>::construct在 中已弃用c++17,而是使用std::allocator_traits::construct