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

fumotvh3  于 2023-05-02  发布在  其他
关注(0)|答案(1)|浏览(193)

我已经用C++20编写了一个无锁和线程安全的环形队列,到目前为止它还可以工作。唯一不完美的是它必须有两个enque()方法,一个接受对左值的const引用作为参数,另一个接受对右值的引用,以便将右值移动到队列中而不是再次构造。
之前的代码版本如下,仅为框架,需要简化:

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.

评论中的所有解决方案都已尝试,没有一个有效。我总是收到一个错误的msg:
类型'std::remove_referencestd::__cxx11::basic_string::type&' {aka 'std::__cxx11::basic_string &'}到'const std::__cxx11::basic_string'的绑定引用会丢弃限定符
如何正确使用std::forward

vq8itlhq

vq8itlhq1#

这个问题与enque()没有正确地转发参数的常数性这一事实有关。这是因为U被推导为const T&,但是在使用std::forward<T>()转发之后,这种恒定性丢失了。为了解决这个问题,只需将std::forward<T>()替换为std::forward<U>()即可
还要注意,c++17中不推荐使用std::allocator<T>::construct,请改用std::allocator_traits::construct

相关问题