2010-12-11 6 views
3

暗黙的な移動変換のためのテンプレートコンストラクタを持つクラスがありますが、このコンストラクタをクラスに使用しないでください(コンストラクタのみコピー可能)。ただし、コンパイラーは、通常のコピーコンストラクターの代わりにテンプレートコンストラクターを常に使用しようとします。テンプレートコンストラクタとテンプレートコピーコンストラクタ

これで、私は、コンパイラのエラー、linkを取得します。いずれかがこれを適切に解決するためにどのようにアイデアを得た

struct implementation{}; 
class my_class 
{ 
my_class(my_class&&); // delete move-constructor... OUCH... COMPILER ERROR 
public: 
my_class(){} 
my_class(const my_class& other) : impl_(other.impl_){} 

template<typename T> 
my_class(T&& impl) : impl_(std::make_shared<T>(std::move(impl))){} // Still tries to use this... 

private: 
std::shared_ptr<implementation> impl_; 
}; 

class other_class 
{ 
public: 
my_class foo() 
{ 
     return instance_; // Wants to use move-constructor??? 
} 
private: 
my_class instance_; 
}; 

(あなたがそれを試してみたい場合は、このコードを貼り付けるだけでコピーすることができますか)?

+0

あなたはリファレンスを参照していますか? o_O –

+0

rvalue-referenceと呼ばれ、http://www.artima.com/cppsource/rvalue.htmlを参照してください。 – ronag

+2

ええ、 '&&'は "論理的な"と "resp"を意味するようになりました。コンテキストに応じて、 "rvalue reference"。トークンリサイクル*素晴らしい*ですか? :) – fredoverflow

答えて

4

わかりましたが、ここでmy_classの私の完全なオーバーホールです:他の人が示唆したように

class my_class 
{ 
public: 
    my_class() {} 
    my_class(my_class&& that) : impl_(std::move(that.impl_)) {} 

    template <typename T> my_class(T&& impl, 
    typename std::enable_if< 
     std::is_base_of< 
      implementation, 
      typename std::remove_reference<T>::type 
     >::value, 
     void 
    >::type* dummy = 0 
    ) : impl_(std::make_shared<T>(std::forward<T>(impl))) {} 

    template <typename T> 
    typename std::enable_if< 
     std::is_base_of< 
      implementation, 
      typename std::remove_reference<T>::type 
     >::value, 
     my_class& 
    >::type 
    operator=(T&& impl) 
    { 
     std::make_shared<implementation>(std::forward<T>(impl)).swap(impl_); 
     return *this; 
    } 

private: 
    std::shared_ptr<implementation> impl_; 
}; 

、これはstd::forward代わりのstd::moveを使用することにより左辺値と右辺値参照のために働きます。左辺参照の場合はTを参照とし、derived&の場合はbaseから派生しないため、derived(参考文献を参照)になるため、remove_referenceが必要です。

+0

それは素晴らしいです。 – ronag

+0

@FredOverflow:暗黙の変換が修正プログラムで動作しないようです。私の編集を参照してください。何か案は? – ronag

+0

@ronag:エラーメッセージから、移動割り当て演算子を指定する必要があるようです。 – fredoverflow

2

これは働くことはできません。

template<typename T> 
my_class(typename std::enable_if<std::is_base_of<implementation, derived_1>::value, T&&>::type impl) : impl_(std::make_shared<T>(std::move(impl))) {} 

template <typename T> 
my_class& operator= (typename std::enable_if<std::is_rvalue_reference<T&&>::value && !std::is_same<T, my_class>::value, T&&>::type impl) 

理由は、あなたが唯一の非推測コンテキストでTを使用することです。明示的に言えば、コンパイラは、それが推論するべき引数がAnything<T>::typeの場合、Tを推論できません。

あなたが代入演算子の上にenable_ifを使いたいのであれば、あなたは戻り値にそれを置く:変換した場合の

template <class T> 
typename enable_if<..., T&>::type operator=(const T&); 

(あまりにも、移動のために働く必要があります)コンストラクタには、ダミーを追加します既定値のパラメータ:

template <class T> 
MyClass(const T&, typename enable_if<..., void>::type* =0); 

FredOverflowは既に正しい代入演算子を返しました。

std::moveの代わりにstd::forwardを使用する場合は、それをrvalue-referencesに制限する必要はありません。 hereを参照してください。それはあなたに与えます(コピー&貼り付けFredOverflowから):

template <typename T> 
typename std::enable_if<std::is_base_of<implementation, T>::value, my_class&>::type 
operator=(T&& impl) 
{ 
    std::make_shared<implementation>(std::forward<T>(impl)).swap(impl_); 
    return *this; 
} 
関連する問題