如何完美地转发一个通用引用,要么是常量引用,要么是可移动的右值?

How to perfectly forward a universal reference that is either a const ref or a movable rvalue?

提问人:Leon 提问时间:4/18/2023 最后编辑:halferLeon 更新时间:5/1/2023 访问量:124

问:

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

代码的先前版本如下,只是一个框架,需要简化:

template <typename T>
class RingQue_t {
public:
    explicit RingQue_t( size_t capacity );
    ~RingQue_t();
    bool deque( T& dest_ ) { return true; };

    // If we offer a const ref, the compiler will select this one
    bool enque( const T& src_ ) {
        // a lot of same codes goes here for a same logic...

        new( _buff + _tail ) T( src_ );
    };

    // If we offer a rvalue ref, the compiler will select this one
    bool enque( T& src_ ) {
        // a lot of same codes goes here for a same logic...

        new( _buff + _tail ) T( std::move( src_ ) );
    };

protected:
    T*  _buff = nullptr;
};

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

template <typename T>
class RingQue_t {
public:
    template<typename U>
    bool enque( U&& src_ ) {
        // new( _buff + _tail ) T( src_ );
        // new( _buff + _tail ) T( std::move( src_ ) );
        // new( _buff + _tail ) T( std::forward<T>( src_ ) );

        std::allocator<T> allc;
        allc.construct( _buff + _tail, std::forward<T>( src_ ) );
        return true;
    };
};

// testing
const std::string s0 { "s0" };
RingQue_t<std::string> str_que( 16 );
str_que.enque( std::string { "s1" } ); // works
str_que.enque( s0 ); // can not pass the compiling.

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

将类型“std::remove_referencestd::__cxx11::basic_string<char >::type&”{aka 'std::__cxx11::basic_string&'} 绑定到“const std::__cxx11::basic_string”的引用丢弃限定符

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

C++ 复制构造函数 rvalue-reference 完美转发 move-constructor

评论

0赞 Eljay 4/18/2023
我无法繁殖。在我清理了缺少的头文件的代码,并删除了编译器显示的所有警告,并修复了所有错误,并添加了缺少的代码,以便示例可以编译和运行......好吧,它编译并运行。也许是一个最小的可重复示例,这样我就可以看到你做了什么我没有做,反之亦然。
6赞 jls28 4/18/2023
我认为std::forward<T>( src_ )是错误的,请使用std::forward<U>( src_ )
0赞 Leon 4/18/2023
哈哈,我的真实代码太多了。如果将它们全部粘贴到这里,则很难阅读,并且这些不相关。我正在编写一个可复制的版本,可以粘贴到这里并且易于阅读。
2赞 NathanOliver 4/18/2023
始终将转发引用类型用于以下模板参数:forwardstd::forward<T>( src_ ) -> std::forward<U>( src_ )
0赞 fabian 4/18/2023
对于 prvalue,重载不适用,至少除非包含修饰符,否则不适用。您需要(这是右值引用,而不是此方案中的转发引用)。bool enque( T& src_ )Tconstbool enque(T&& src_)

答:

6赞 Cosemuckel 4/18/2023 #1

proplem 与事实有关,这不能正确地转发论点的恒常性。这是因为被推导出为 ,但是在使用此常量转发后就丢失了。为了解决这个问题,只需将enque()Uconst T&std::forward<T>()std::forward<T>()std::forward<U>()

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

评论

0赞 user17732522 4/18/2023
"在 C++17 中已弃用“:并在 C++ 20 中删除。所以它甚至不会再编译了。