2012-12-30 6 views
5

は、次のように私たちは、クラスのボックスを持っていると仮定し適切なストレージ値のタイプを取得していますか?</p> <pre><code>struct Base {} template<typename T> struct Box : Base { template<typename... Args> Box(Args&&... args) : t(forward<Args>(args)...) {} T t; } </code></pre> <p>をそして、我々は関数MakeBoxがあります:

template<typename X> 
Base* MakeBox(X&& x) 
{ 
    return new Box<???>(forward<X>(x)); 
} 

タイプXがMakeBoxへの呼び出しで使用されるパラメータから推定されます。私たちは、その後、適切な「ストレージタイプ」パラメータT.

Xから何とか計算する必要があり

我々はただ単純に使用している場合、私は思う:

return new Box<X>(forward<X>(x)); 

、これは問題が発生します。

明らかにstd::bindstd::functionは、これらの問題に対処する必要があります。

とにかくstd::decayはここでは役に立ちますか?

+0

あなたは探しているものが['std :: remove_reference '](http://en.cppreference.com/w/cpp/types/remove_reference)ではありませんか? – jogojapan

+0

@jogojapan: 'std :: bind'がバインドされたパラメータを格納するために使用するものですか? –

+3

'std :: decay'はまさにあなたが探しているものです。 – Mankarse

答えて

1

提供されている例では、(1)は値を保存して保存します。他の場合(xが配列の場合など)は、std::decayを使用してポインタに壊して格納することができます。

3

あなたが達成したいことを正しく理解している場合は、std::decayを使用する必要があります。 SのオブジェクトをMakeBox()に指定している場合、ユニバーサル参照X&&は、引数がそれぞれ左辺値か右値かに応じてタイプS&またはS&&のいずれかの関数引数を作成するように解決されます。あなたのメンバ変数をする必要があるため、(ここでXは、Box<>の引数としてOKではないでしょう、これを達成するために起因普遍的な参照のためのC++ 11個のルールに、最初のケースではテンプレート引数がX=S&と推測されます

オブジェクト参照ではなくオブジェクト参照)、第2の場合はX=S(ここではXBox<>の引数として問題ありません)と推定されます。あなたにも暗黙的にBox<>にテンプレート引数としてそれを供給する前に推定されたタイプXstd::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に尋ねた。

+0

'std :: decay'についてはどうですか? –

+0

確かに 'std :: decay'は良いオプションと思われます。これは' std :: remove_reference <> 'も同様に含まれているためです。私が最初にそれを考慮しなかった理由は、 'const'修飾子を取り除くことですが、' const'修飾子を保持したくないことに気付きました。なぜなら、内部に新しいオブジェクトを作成しているからです'Box'のコピーコンストラクタを呼び出します。もしそうなら、実際に私の答えで 'std :: remove_reference'を' std :: decay'に置き換えることができます。私はそれを行い、適切な信用を与えるでしょう。 –

+0

関数 'MakeBox <>()'とクラス 'Box <>'に関してBtwは常に 'T'のコピーコンストラクタを常に呼びたいと思っていますか? 'Box'のコンストラクタに' T'のコンストラクタに引数を転送する引数パックがありますが、入力に常に1つの 'T'オブジェクトしか渡さず、常にコピーコンストラクタを呼び出します。あなたは 'MakeBox <>()'にも変数リストを持っていてはいけませんか? Btw、Baseを返すのではなく、正確なポインタ( 'Box :: type> *')を返します。 –

関連する問題

 関連する問題