首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >默认的移动赋值不能显式为non,除非成员具有非平凡的no以外的赋值运算符。

默认的移动赋值不能显式为non,除非成员具有非平凡的no以外的赋值运算符。
EN

Stack Overflow用户
提问于 2013-12-16 12:10:28
回答 1查看 3.3K关注 0票数 15

此代码无法用gcc 4.8.2 (-std=c++11)编译,但使用clang3.4(主干)(-std=c++11)编译:

代码语言:javascript
复制
#include <type_traits>
#include <vector>

struct X {
  X& operator=(X&&) noexcept = default;
  // adding noexcept this leads to an error in gcc, but works in clang:
  // function ‘X& X::operator=(X&&)’ defaulted on its first
  // declaration with an exception-specification that differs from the
  // implicit declaration ‘X& X::operator=(X&&)’

  std::vector<char> m;
};

// this assert holds, even without noexcept
static_assert(std::is_nothrow_move_assignable<X>::value, 
              "type-specification violation");

int main()
{
  return 0;
}

static_assert是gcc有趣的部分:默认的移动任务将是noexcept,但我不能这样声明。

不涉及vector的一种变体是:

代码语言:javascript
复制
template<bool b>
struct F {
  F& operator=(F&&) noexcept(b) {return *this;}
};

struct X {
  X& operator=(X&&) noexcept = default;
  F<true> f;
};

这里的预期行为是什么?从直觉上讲,嘎嘎声似乎是正确的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-12-16 17:13:18

不涉及vector的示例应该编译。在这个问题上,clang是正确的。

涉及vector的示例可能编译也可能不编译,这取决于std::lib供应商是否将vector的移动赋值操作符标记为noexcept。标准不要求此签名为noexcept。如果该函数永远不会抛出,则该标准允许供应商添加noexcept

libc++vector移动赋值操作符标记为noexcept,如果allocator_traits<allocator_type>::propagate_on_container_move_assignment::value为true,而is_nothrow_move_assignable<allocator_type>::value为true (作为符合条件的扩展)。在用于libc++的std::allocator<T>实现中,这两者都是正确的。

更新

应要求拔出语言律师帽。

<disclaimer>

我在半个不属于我的专业领域的标准中四处游逛。

</disclaimer>

你能更清楚地说明为什么要编译这个例子吗?

所有的引号都来自于最新的C++1y工作草案,N3797

这指定在显式默认特殊成员上允许异常规范:

8.4.2 显式地-默认函数 dcl.fct.def.default/p2

2只有当显式默认函数被隐式声明为constexpr时,它才能被声明为constexpr,并且只有当它与隐式声明上的异常规范兼容(15.4)时,它才可能具有显式的异常规范。

这定义了“兼容异常-规范:”

15.4 异常规范(规范/p3除外)

3两个例外-在下列情况下,规范是兼容的:

  • 两者都是不抛的(见下文),无论它们的形状如何,
  • 两者都有形式noexcept(常量表达式)和常量表达式是等价的,或者
  • 两者都是具有相同调整类型集的动态异常规范.

二号子弹覆盖了你的案子。

这解释了为什么在您的示例中隐式声明的特殊成员是noexcept

15.4 异常规范(规范/p14除外)

14继承构造函数(12.9)和隐式声明的特殊成员函数(第12条)具有异常规范。如果f是继承构造函数或隐式声明的默认构造函数、复制构造函数、移动构造函数、析构函数、复制赋值运算符或移动赋值操作符,则其隐式异常规范指定类型id T当且仅当Tf的隐式定义直接调用的函数规范所允许时;如果直接调用的任何函数都允许所有异常,则f允许所有异常;如果直接调用的每个函数都不允许异常,则f具有异常规范noexcept(true)

因为隐式声明的X& operator=(X&&)调用的每个函数都不允许异常(即F<true>的移动赋值操作符),所以这个特殊成员是noexcept(true)

我相信那能把它钉下来。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20610658

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档