由于我已将移动分配运算符声明为noexcept,因此以下结构在C++ 11下无法编译:

struct foo
{
  std::vector<int> data;
  foo& operator=(foo&&) noexcept = default;
};

由于noexcept(false)的移动分配也是std::vector<int>,因此编译器生成的默认移动分配操作符为noexcept(false)。这又是由于默认分配器已将std::allocator_traits<T>:: propagate_on_container_move_assignment设置为std::false_type而导致的。另请参见this question

我相信这已在C++ 14中修复(请参阅library defect 2103)。

我的问题是,是否有一种方法可以将noexcept强制设置为默认的移动分配赋值运算符,而无需自己定义?

如果这不可能,是否有办法欺骗std::vector<int>使其成为可分配的noexcept,以便noexcept(true)传递给我的结构?

最佳答案



作为DR,该修复程序应被视为对C++ 11的更正,因此某些C++ 11实现已对其进行了修复。



为了使默认的移动分配运算符为noexcept,您需要使其子对象具有noexcept移动分配运算符。

我能想到的最明显的便携式方法是在std::vector周围使用包装器,以强制将其移动为noexcept

template<typename T, typename A = std::allocator<T>>
  struct Vector : std::vector<T, A>
  {
    using vector::vector;

    Vector& operator=(Vector&& v) noexcept
    {
      static_cast<std::vector<T,A>&>(*this) = std::move(v);
      return *this;
    }
    Vector& operator=(const Vector&) = default;
  };

另一个类似的选项是使用DR 2013修复程序定义自己的分配器类型,并使用该类型:
template<typename T>
  struct Allocator : std::allocator<T>
  {
    Allocator() = default;
    template<typename U> Allocator(const Allocator<U>&) { }
    using propagate_on_container_move_assignment  = true_type;
    template<typename U> struct rebind { using other = Allocator<U>; };
  };

template<typename T>
  using Vector = std::vector<T, Allocator<T>>;

另一个选择是使用诸如GCC之类的标准库实现,该实现实现DR 2013的分辨率,并且在已知所有分配器实例比较相等的情况下,还使std::vector的移动分配运算符noexcept用于其他分配器类型。

关于c++ - 我可以强制默认特殊成员函数为noexcept吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18730969/

10-13 06:43