2016-10-07 7 views
2

最初にエラーメッセージが表示されています。 "引数"という言葉の後に引用符だけがあります。それは、それ自身では不思議です。しかし、ここで私が解決しようとしている問題があります。私は内部的に入力しても、コンバーチブル型を受け入れる必要があります(テンプレート)の参照を格納するクラスを書いている:候補テンプレートが無視されました:テンプレート引数を推測できませんでした。 '

template<typename T> 
class Ref { 
public: 
    Ref(); 
    Ref(std::nullptr_t); 
    explicit Ref(T *value); 

    Ref(Ref const& value); 

    template<typename T2, typename std::enable_if<std::is_convertible<T2*, T*>::value, T2>::type> 
    Ref(Ref<T2> const& value); 

    template<typename T2, typename std::enable_if<std::is_convertible<T2*, T*>::value, T2>::type> 
    Ref(Ref<T2> &&value); 
private: 
    T *_value; 
}; 

は、今私は2クラスAとBがあります。

class A { 
}; 

class B : public A { 
}; 

をし、しようとしていますクラスAのための文献変数にBのための参考文献のインスタンスを割り当てることが:

Ref<B> t; 
Ref<A> t2(t); 

をこれが実際にコンパイルする必要があり、私は最後の2つのコンストラクタ(コンバーチブル型をとるもの)のために記載されたエラー(打ち鳴らす)を取得し、そのsh ouldは実際に割り当てられています。ここでテンプレート引数の控除を行うには何が必要ですか?

答えて

7

あなたが誤ってstd::enable_ifを使用している、これは次のようになります。ここでは

template<typename T2, 
     typename = 
      typename std::enable_if<std::is_convertible<T2*, T*>::value>::type> 
Ref(Ref<T2> const& value); 

、2番目のテンプレート引数は何である、T2*T1*に変換できない場合は失敗するだろう何かにデフォルト設定されています欲しい:

  • std::is_convertible<T2*, T*>::valuetrueであれば、これは同等です:
template<typename T2, typename = void> // Ok, well-formed 
Ref(Ref<T2> const& value); 
  • そうしないと、あなたが得る:
  • あなたの元のコードで
template<typename T2, typename = /* Something ill-formed */> 
Ref(Ref<T2> const& value); 

std::enable_ifが成功したとき、あなたのテンプレートは同等であった:

template<typename T2, typename T2> // Well-formed, but T2 cannot be deduced 
Ref(Ref<T2> const& value); 

これはあなたが望んでいなかったものです(この場合、コンパイラはT2を推測できませんでした)。

あなたがC++ 14へのアクセス権を持っている場合は、std::enable_if_t<>typename std::enable_if<>::typeを置き換えることができます。

これは、1つの可能性は、std::enable_if_t<..., int> = 0(または同様のもの)を使用している他の1ですが、私はtypename = ...とバージョンを好みます。一般的なケースでは厳密には同等ではありませんが、この場合は重要ではありません。

2

ホルトの答えを完了するには、デフォルトのコンストラクタとコンストラクタをnullptr_tでマージしてRef(std::nullptr_t = nullptr):_value{nullptr} {}にすることができます。

Ref(Ref const& value);は、Ref(Ref<T2> const& value);と同じです。T2=Tです。

あなたのスニペットには、operator=がありません。 copy and swap idiomを使用して、T2に少しテストを因数分解するためにそれを使用することがあります。

template<typename T> 
class Ref { 
public: 
    Ref(std::nullptr_t = nullptr):_value{nullptr} {} 
    explicit Ref(T *value); 

    template<typename T2, typename = typename std::enable_if<std::is_convertible<T2*, T*>::value, T2>::type> 
    Ref(Ref<T2> const& value); 

    template<typename T2> 
    Ref(Ref<T2> &&value):Ref{} 
    { 
     swap(*this, value); 
    } 

    template<typename T2> 
    Ref& operator=(Ref<T2> value) 
    { 
     swap(*this, value); 
     return (*this); 
    } 

    template<typename T1, typename T2, typename = typename std::enable_if<std::is_convertible<T2*, T1*>::value>::type> 
    friend void swap(Ref<T1>& t1, Ref<T2>& t2) 
    { 
     using std::swap; 
     swap(t1._value, t2._value); 
    } 
private: 
    T *_value; 
}; 
+0

ここでは、簡単にするために代入演算子implsを省略しましたが、インターフェイスを簡素化するヒントについては感謝します。 –

4

@Holt's answerいいですし、正しくごstd::enable_ifを使用する方法について説明します。

とにかく、この場合は、まったく使用する必要はありません。
static_assertここで十分であるとのエラーメッセージがそれで立派になります。

template<typename U> 
Ref(Ref<U> const& value) { 
    static_assert(std::is_convertible<U, T>::value, "!"); 
    // whatever you want 
} 

template<typename U> 
Ref(Ref<U> &&value) { 
    static_assert(std::is_convertible<U, T>::value, "!"); 
    // whatever you want 
} 

、この(CAに変換できない場合)のようなもの:

Ref<A> t3(Ref<C>{}); 

はあなたにエラーを与えます

error: static assertion failed: ! static_assert(std::is_convertible::value, "!");

Sfinaeの表現は通常(私に言わせてください)選択を有効または無効にする
正しい選択肢を選ぶ有効な選択肢がない場合は、通常はstatic_assertが好ましいです。

関連する問題