Clang和GCC vs MSVC和ICC:复制/移动构造函数中的static_assert是否需要工作,如果复制/移动省略也适用?

Rum*_*rak 24 c++ static-assert language-lawyer copy-elision c++11

我有一个我static_assert的模板结构的移动构造函数.这是否static_assert需要编译器考虑,即使可以复制省略?

这是精简的场景:

#include <type_traits>

template<typename T>
struct X
{
  X(X&&) { static_assert(std::is_same<void, T>::value, "Intentional Failure"); }
};

auto impl() -> X<int>;    
auto test() -> decltype(impl())
{
  return impl();
}

int main()
{
  test();
}
Run Code Online (Sandbox Code Playgroud)

GCC和Clang同意评估static_assert并且无法编译.
另一方面,MSCV和ICC编译代码就好了.

有趣的是,当我删除move构造函数的定义时,只需将其声明为:

template<typename T>
struct X
{
  X(X&&);
};
Run Code Online (Sandbox Code Playgroud)

GCC和Clang现在也编译代码.因此,所有编译器似乎都同意移动构造函数的定义与复制省略无关.

问题:
如果static_assert复制/移动构造函数中有a ,即使可以复制/移动省略,标准是否要求对其进行评估?

And*_*zej 4

以下内容应该有所帮助。

您不必使用类型推导来说明问题。即使是更简单的例子也有同样的问题:

#include <type_traits>

template <typename T>
struct X
{
  X() {}
  X(X&&) { static_assert(std::is_same<void, T>::value, "failed"); }
};

int main()
{
  X<int> x = X<int>();
}
Run Code Online (Sandbox Code Playgroud)

Clang 和 GCC 不会编译它。MSVC 编译并执行良好。

这表明问题与 odr 使用以及实例化成员函数的定义有关。

14.7.1 [temp.inst] 第 2 段说“[...] 当在需要成员定义存在的上下文中引用专门化时,成员的专门化将被隐式实例化”

3.2 [basic.def.odr] 第 3 段(在注释中)说“[...] 选择用于复制或移动类类型对象的构造函数是 odr 使用的,即使该调用实际上被实现省略了”

3.2 [basic.def.odr] 第 4 段说“每个程序都应包含该程序中 odr 使用的每个非内联函数或变量的一个定义;不需要诊断。”

因此:专业化应该被实例化,并且断言已经触发。