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));
}
};
我希望BlockingQueue :: push方法能够处理类型为T的对象的rvalue和lvalue引用,以将其转发到std::queue::push
正确的版本。
是不是喜欢上面的代码,或者在我的BlockingQueue
类中提供两种版本的push方法?一个用于左值,一个用于右值
答案 0 :(得分:7)
实施对我来说似乎是正确的,并且完成了这项工作。
然而,在你的情况下,为左值和右值提供不同的实现可能是个好主意。 (我能想到的)主要原因是扣除模板类型参数不适用于 braced-init-lists 。考虑:
struct foo {
foo(std::initializer_list<int>) {
}
};
// ...
foo f{1, 2, 3}; // OK
BlockingQueue<foo> b;
使用OP的代码(*)
b.push(f); // OK
b.push({1, 2, 3}); // Error
相反,如果提供了BlockingQueue::push
的以下重载:
void push(const T& value) {
container_.push(value);
}
void push(T&& value) {
container_.push(std::move(value));
}
然后,以前失败的行将正常工作。
相同的参数适用于聚合。例如,如果foo
被定义为
struct foo {
int a, b, c;
};
人们会观察到上述相同的行为。
我的结论是,如果您希望BlockingQueue
支持更多类型(包括构造函数采用std::initializer_list
s的聚合或类型),那么最好提供两个不同的重载。
(*)OP代码中的一个小修正:在static_assert
中你需要使用typename
typename std::remove_reference<U>::type>::value
^^^^^^^^
答案 1 :(得分:0)
如果您想使用完美转发,我建议您使用emplace
类的queue
方法。 emplace
方法将给定参数转发给T
构造函数。无需检查T
是否与U
相同。只要T
可以从U
构造,它就应该编译。此外,如果您愿意,可以使用可变参数模板参数。
template<typename... Args>
void push(Args&&... args)
{
container_.emplace(std::forward<Args>(args)...);
}
因此,只要T可以从给定的参数构造,就可以推送任何你想要的东西。