这是一个需要完美转发的经典例子。通过模板化函数来做到这一点(如果这是成员函数,则为成员模板):
template <class U>
void enqueue(U&& item)
{
std::unique_lock<std::mutex> lock(m);
this->push(std::forward<U>(item));
this->data_available = true;
cv.notify_one();
}
解释:如果你将左值T 传递给enqueue,U 将推导出为T&,forward 将它作为左值传递,你将得到你的复制行为想。如果你将右值T 传递给enqueue,U 将推导出为T,forward 会将它作为右值传递,你将得到你想要的移动行为。
这比“按值传递”方法更有效,因为您永远不会进行不必要的复制或移动。 “按值传递”方法的缺点是该函数接受任何内容,即使它是错误的。您可能会或可能不会在push 下遇到级联错误。如果这是一个问题,您可以enable_if enqueue 来限制它将使用哪些参数进行实例化。
根据评论更新
根据下面的 cmets,这是我理解的样子:
#include <queue>
#include <mutex>
#include <condition_variable>
template <class T>
class Mine
: public std::queue<T>
{
std::mutex m;
std::condition_variable cv;
bool data_available = false;
public:
template <class U>
void
enqueue(U&& item)
{
std::unique_lock<std::mutex> lock(m);
this->push(std::forward<U>(item));
this->data_available = true;
cv.notify_one();
}
};
int
main()
{
Mine<int> q;
q.enqueue(1);
}
这一切都很好。但是,如果您尝试将双精度排入队列会怎样:
q.enqueue(1.0);
这仍然有效,因为 double 可以隐式转换为 int。但是,如果您不希望它工作怎么办?然后你可以像这样限制你的enqueue:
template <class U>
typename std::enable_if
<
std::is_same<typename std::decay<U>::type, T>::value
>::type
enqueue(U&& item)
{
std::unique_lock<std::mutex> lock(m);
this->push(std::forward<U>(item));
this->data_available = true;
cv.notify_one();
}
现在:
q.enqueue(1.0);
结果:
test.cpp:31:11: error: no matching member function for call to 'enqueue'
q.enqueue(1.0);
~~^~~~~~~
test.cpp:16:13: note: candidate template ignored: disabled by 'enable_if' [with U = double]
std::is_same<typename std::decay<U>::type, T>::value
^
1 error generated.
但是q.enqueue(1); 仍然可以正常工作。 IE。限制您的成员模板是您需要做出的设计决定。你想让enqueue 接受什么U?没有正确或错误的答案。这是一个工程判断。还有其他一些可能更合适的测试可用(例如 std::is_convertible、std::is_constructible 等)。可能对您的应用程序的正确答案是完全没有约束,就像上面最初的原型一样。