これは、完全に転送する必要がある典型的な例です。これを行うには、関数(これがメンバー関数の場合はメンバーテンプレート)をテンプレート化します。
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);
}
これはすべて良いです。しかし、代わりにdoubleをエンキューしようとするとどうなりますか?
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など)。上で最初にプロトタイプを作成したように、アプリケーションの正しい答えはまったく制約がないかもしれません。