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.

如何在不使用链接问题中描述的技巧的情况下纠正此错误?

谢谢!

编辑: 最让我困惑的是为什么没有调用两个专门的构造函数。他们更适合通话。

  // 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

他们现在将得到正确的答案。正如您目前对其进行编码的那样,上述特征总是回答正确。

于 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 回答