あなたが達成したいことを正しく理解している場合は、std::decay
を使用する必要があります。 S
のオブジェクトをMakeBox()
に指定している場合、ユニバーサル参照X&&
は、引数がそれぞれ左辺値か右値かに応じてタイプS&
またはS&&
のいずれかの関数引数を作成するように解決されます。あなたのメンバ変数をする必要があるため、(ここでX
は、Box<>
の引数としてOKではないでしょう、これを達成するために起因普遍的な参照のためのC++ 11個のルールに、最初のケースではテンプレート引数がX=S&
と推測されます
オブジェクト参照ではなくオブジェクト参照)、第2の場合はX=S
(ここではX
はBox<>
の引数として問題ありません)と推定されます。あなたにも暗黙的にBox<>
にテンプレート引数としてそれを供給する前に推定されたタイプX
にstd::remove_reference
を適用するstd::decay
を適用することで、あなたはX
は常にS
、決してS&
等しいであろうことを確認してくださいしようとしている(X
がであることを、覚えておいてください。はS&&
と推測されません。S
またはS&
のいずれかになります。
#include <utility>
#include <type_traits>
#include <iostream>
using namespace std;
struct Base {};
template<typename T>
struct Box : Base
{
template<typename... Args>
Box(Args&&... args)
: t(forward<Args>(args)...)
{
}
T t;
};
template<typename X>
Base* MakeBox(X&& x)
{
return new Box<typename decay<X>::type>(forward<X>(x));
}
struct S
{
S() { cout << "Default constructor" << endl; }
S(S const& s) { cout << "Copy constructor" << endl; }
S(S&& s) { cout << "Move constructor" << endl; }
~S() { cout << "Destructor" << endl; }
};
S foo()
{
S s;
return s;
}
int main()
{
S s;
// Invoking with lvalue, will deduce X=S&, argument will be of type S&
MakeBox(s);
// Invoking with rvalue, will deduce X=S, argument will be of type S&&
MakeBox(foo());
return 0;
}
興味のある方は、ここで彼は普遍的な参照がどのように動作するかを説明し、スコット・マイヤーズ非常に良い教訓がある:
Scott Meyers on universal references
PS:この答えはが編集されている:私のオリジナル答えはstd::remove_reference<>
を使用するように提案されましたが、std::decay
がより良い選択であることが判明しました。質問ポスターへのクレジット@Andrew Tomazos FathomlingCorpsは、それを指摘し、元の質問へのコメントでそれを最初に提案した@Mankarseに尋ねた。
あなたは探しているものが['std :: remove_reference'](http://en.cppreference.com/w/cpp/types/remove_reference)ではありませんか? –
jogojapan
@jogojapan: 'std :: bind'がバインドされたパラメータを格納するために使用するものですか? –
'std :: decay'はまさにあなたが探しているものです。 – Mankarse