pmr*_*pmr 15 c++ assignment-operator move-semantics c++11
此代码无法使用gcc 4.8.2(-std = c ++ 11)进行编译,但使用clang 3.4(trunk)编译(-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;
}
Run Code Online (Sandbox Code Playgroud)
这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;
};
Run Code Online (Sandbox Code Playgroud)
这里的预期行为是什么?直觉铿锵似乎是正确的.
不涉及的例子vector应该编译。clang 在这一点上是正确的。
所涉及的示例vector可能编译也可能不编译,这取决于 std::lib 供应商是否已将移动赋值运算符标记为vectorasnoexcept与否。该标准不要求此签名为noexcept. 该标准确实允许供应商添加noexcept该函数是否永远不会抛出。
libc++将vector移动赋值运算符标记为noexceptifallocator_traits<allocator_type>::propagate_on_container_move_assignment::value为真且is_nothrow_move_assignable<allocator_type>::value为真(作为符合扩展的)。在 libc++ 的std::allocator<T>.
更新
应要求拔掉语言律师的帽子。
<disclaimer>
我在标准的一半中闲逛,这不是我的专业领域。
</disclaimer>
你能更明确地解释为什么这个例子应该编译吗?
所有引用均来自最新的 C++1y 工作草案N3797。
这指定在显式默认的特殊成员上允许异常规范:
8.4.2显式默认函数[dcl.fct.def.default]/p2
2 显式默认函数
constexpr只有在隐式声明为 时才可以声明constexpr,并且只有当它与隐式声明中的异常规范兼容 (15.4) 时才可以具有显式异常规范。
这定义了“兼容的异常规范:”
15.4异常规范[except.spec]/p3
3 在以下情况下,两个异常规范是兼容的:
两者都是非投掷(见下文),无论其形式如何,
两者都具有形式
noexcept( constant-expression ) 并且constant-expression是等效的,或者两者都是具有相同调整类型集的动态异常规范。
Bullet 2 涵盖了您的情况。
这解释了为什么隐式声明的特殊成员noexcept在您的示例中:
15.4异常规范[except.spec]/p14
14 继承构造函数(12.9)和隐式声明的特殊成员函数(第 12 条)具有异常规范。如果 f 是继承构造函数或隐式声明的默认构造函数、复制构造函数、移动构造函数、析构函数、复制赋值运算符或移动赋值运算符,则其隐式 异常规范指定type-id
T当且仅当异常T允许时-由的隐式定义直接调用的函数的规范f;f如果它直接调用的任何函数允许所有异常,并且f具有 异常规范,则允许所有异常noexcept(true)如果它直接调用的每个函数都不允许例外。
因为由隐式声明调用的每个函数都X& operator=(X&&)不允许出现异常(即 的移动赋值运算符F<true>),所以这个特殊成员是noexcept(true)。
我相信这可以解决问题。