此代码无法用gcc 4.8.2 (-std=c++11)编译,但使用clang3.4(主干)(-std=c++11)编译:
#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的一种变体是:
template<bool b>
struct F {
F& operator=(F&&) noexcept(b) {return *this;}
};
struct X {
X& operator=(X&&) noexcept = default;
F<true> f;
};这里的预期行为是什么?从直觉上讲,嘎嘎声似乎是正确的。
发布于 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当且仅当T被f的隐式定义直接调用的函数规范所允许时;如果直接调用的任何函数都允许所有异常,则f允许所有异常;如果直接调用的每个函数都不允许异常,则f具有异常规范noexcept(true)。
因为隐式声明的X& operator=(X&&)调用的每个函数都不允许异常(即F<true>的移动赋值操作符),所以这个特殊成员是noexcept(true)。
我相信那能把它钉下来。
https://stackoverflow.com/questions/20610658
复制相似问题