std:在模板类中转发

Gui*_*e07 6 c++ rvalue-reference c++11

 template<typename T>
   class BlockingQueue
   { 
       std::queue<T> container_;

       template< typename U >
       void push(U&& value)
       {
           static_assert(std::is_same<T, typename std::remove_reference<U>::type>::value,"Can't call push without the same parameter as template parameter's class");

           container_.push(std::forward<U>(value)); 
       }
};
Run Code Online (Sandbox Code Playgroud)

我想BlockingQueue :: push方法能够处理类型为T的对象的rvalue和lvalue引用,以将其转发到 std::queue::push正确的版本.是不是喜欢上面的代码,或者在我的BlockingQueue类中提供两个版本的push方法?一个用于左值,一个用于右值

Cas*_*eri 7

实施对我来说似乎是正确的,并且完成了工作.

然而,在你的情况下,为左值和右值提供不同的实现可能是一个好主意.(我能想到的)主要原因是扣除模板类型参数不适用于braced-init-lists.考虑:

struct foo {
    foo(std::initializer_list<int>) {
    }
};

// ...
foo f{1, 2, 3};    // OK

BlockingQueue<foo> b;
Run Code Online (Sandbox Code Playgroud)

使用OP的代码(*)

b.push(f);         // OK
b.push({1, 2, 3}); // Error
Run Code Online (Sandbox Code Playgroud)

相反,如果BlockingQueue::push提供以下重载:

void push(const T& value) {
    container_.push(value); 
}

void push(T&& value) {
    container_.push(std::move(value)); 
}
Run Code Online (Sandbox Code Playgroud)

然后,以前失败的行将正常工作.

相同的参数适用于聚合.例如,如果foo被定义为

struct foo {
    int a, b, c;
};
Run Code Online (Sandbox Code Playgroud)

人们会观察到上述相同的行为.

我的结论是,如果你想BlockingQueue支持更多类型(包括带有构造函数的聚合或类型std::initializer_list),那么最好提供两个不同的重载.

(*)OP代码中的一个小修正:在static_assert你需要使用的时候typename

typename std::remove_reference<U>::type>::value
^^^^^^^^
Run Code Online (Sandbox Code Playgroud)