3

単純なコンテナークラスを構築していますが、いくつかの問題が発生します(Visual C ++ 2010でのコンテナーの再アセンブル、右辺値参照のバグ?

#include <cassert>
#include <utility>

template<typename T0>
class MyType {
 public:
  typedef T0 value_type;

  // Default constructor
  MyType() : m_value() {
  }

  // Element constructor
  explicit MyType(const T0 &c_0) : m_value(c_0) {
  }

  template<typename S0>
  explicit MyType(S0 &&c_0) : m_value(std::forward<S0>(c_0)) {
  }

  // Copy constructor
  MyType(const MyType &other) : m_value(other.m_value) {
  }

  MyType(MyType &&other) : m_value(std::forward<value_type>(other.m_value)) {
  }

  // Copy constructor (with convertion)
  template<typename S0>
  MyType(const MyType<S0> &other) : m_value(other.m_value) {
  }

  template<typename S0>
  MyType(MyType<S0> &&other) : m_value(std::move(other.m_value)) {
  }

  // Assignment operators
  MyType &operator=(const MyType &other) {
    m_value = other.m_value;
    return *this;
  }

  MyType &operator=(MyType &&other) {
    m_value = std::move(other.m_value);
    return *this;
  }

  template<typename S0>
  MyType &operator=(const MyType<S0> &other) {
    m_value = other.m_value;
    return *this;
  }

  template<typename S0>
  MyType &operator=(MyType<S0> &&other) {
    m_value = std::move(other.m_value);
    return *this;
  }

  // Value functions
  value_type &value() {
    return m_value;
  }

  const value_type &value() const {
    return m_value;
  }

 private:
  template<typename S0>
  friend class MyType;

  value_type m_value;
};

int main(int argc, char **argv) {
  MyType<float>  t1(5.5f);
  MyType<double> t2(t1);

    return 0;
}

上記のコードは次のエラーを出します:

1>ClCompile:
1>  BehaviorIsolation.cpp
1>behaviorisolation.cpp(18): error C2440: 'initializing' : cannot convert from 'MyType<T0>' to 'double'
1>          with
1>          [
1>              T0=float
1>          ]
1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>          behaviorisolation.cpp(78) : see reference to function template instantiation 'MyType<T0>::MyType<MyType<float>&>(S0)' being compiled
1>          with
1>          [
1>              T0=double,
1>              S0=MyType<float> &
1>          ]
1>behaviorisolation.cpp(18): error C2439: 'MyType<T0>::m_value' : member could not be initialized
1>          with
1>          [
1>              T0=double
1>          ]
1>          behaviorisolation.cpp(73) : see declaration of 'MyType<T0>::m_value'
1>          with
1>          [
1>              T0=double
1>          ]
1>
1>Build FAILED.

リンクされた質問で説明されているようなトリックを使用せずに、このエラーをどのように修正できますか?

ありがとう!

編集: 私を最も混乱させるのは、2つの特殊なコンストラクターのいずれも呼び出されない理由です。彼らは電話に非常によく合います。

  // Copy constructor (with convertion)
  template<typename S0>
  MyType(const MyType<S0> &other) : m_value(other.m_value) {
  }

  template<typename S0>
  MyType(MyType<S0> &&other) : m_value(std::move(other.m_value)) {
  }
4

2 に答える 2

2

コンストラクター:

 template<typename S0>
  explicit MyType(S0 &&c_0)

は過度に一般的であり、問​​題を解決する最良の方法は、として推定できるタイプを制限することS0です。これは基本的にリンクされた答えがすることです。しかし、おそらく私はあなたのためにそれをより美しくすることができます。

これが、std :: C ++ 11にあります:

  template<typename S0,
           class = typename std::enable_if
           <
               std::is_convertible<S0, T0>::value
           >::type>
  explicit MyType(S0 &&c_0) : m_value(std::forward<S0>(c_0)) {
  }

それがあまりにも醜い場合は、次のことを検討してください。

#define restrict_to(x...) class = typename std::enable_if<x>::type

..。

template<typename S0, restrict_to(std::is_convertible<S0, T0>::value)>
explicit MyType(S0 &&c_0) : m_value(std::forward<S0>(c_0)) {
}

これは問題を解決するだけでなく、クライアントがその後次のような質問をする場合にも注意してください。

std::is_convertible<X, MyType<T>>::type

彼らは今正しい答えを得るでしょう。現在コーディングしているので、上記の特性は常にtrueと答えます。

于 2011-08-09T00:57:11.870 に答える
2

あなたのリンクされた質問はすでにこれに答えています。定義しましょう

typedef MyType<float>  MF;
typedef MyType<double> MD;

と言うときはMD t2(t1);、コンストラクターを呼び出しますMF::MF(const MD &)。ただし、コンストラクターはより適切に一致します。これは、template <typename T> MF::MF(T&&)が必要T = MD&であり、したがって、に解決されるためです。MF::MF(MD&)これは、がないため、より適切に一致しconstます。

MF(T&&)これを解決するには、ハワードがすでに提案したように、基本的にコンストラクターを取り除く必要があります。とにかく値のコンストラクターだけを意図しているので、私の最初の提案は、署名をに変更するMF(const T &)ことです。これにより、問題はすでに解決されます。別の解決策は、署名付きのコンストラクターMF(MD&)(非定数)を追加することです。しかし、それは醜いです。最後に、呼び出しサイトでコンストラクターを明示的に呼び出すことができます。オプションの場合は、、MD t2(MF(t1))またはMD t2(std::forward<MF>(t1))、さらには。MD t2(std::move(t1))

最後に、プリミティブメンバーのみを扱っている場合は、明示的な移動から得られるものは何もないため、これらすべてのコンストラクターを個別に定義する必要はないことに注意してください。

于 2011-08-09T01:10:06.857 に答える