这是一个需要完美转发的经典例子。通过模板函数来做到这一点(如果这是成员函数,则为成员模板):
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
限制它将实例化的参数。
根据评论更新
根据下面的评论,这就是我理解的情况:
#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);
仍然可以正常工作。即限制您的成员模板是您需要做出的设计决定。你U
想enqueue
接受什么?没有正确或错误的答案。这是一个工程判断。还有其他一些可能更合适的测试可用(例如 std::is_convertible、std::is_constructible 等)。就像上面最初的原型一样,对于您的应用程序来说,也许正确的答案是完全没有约束。