为什么使用非平凡的析构函数(例如 unique_ptr、std::variant)为 类 声明 constrexpr 构造函数

why declare constrexpr constructors for classes with non-trivial destructors (e.g. unique_ptr, std::variant)

据我了解(至少对于 c++14),如果析构函数不是微不足道的(隐式生成或 =default),则析构函数不能是 constexpr。为具有非平凡析构函数的结构声明 constexpr 构造函数有什么意义?

struct X {
  int a_;

  constexpr X(int a) : a_{a} {}

  // constexpr ~X(){}; // Error dtor cannot be marked constexpr
  // ~X(){}; // causes  error at y declaration: temporary of non-literal type ‘X’
             // in a constant expression .
};

template <int N> struct Y {};

int main() {
  Y<X{3}.a_> y; // OK only if the destructor is trivial
  (void)y;
}
// tested with c++14 g++-5.1.0 and clang++ 3.5.0

例如 std::unique_ptr 有一些 constructors constexpr(默认和 nullptr_t),即使析构函数显然是显式定义的(如果object 是 nullptr,但这并不意味着它仍然有一个显式定义的析构函数来检查对象是否处于空状态,正如我所看到的,即使是一个空的析构函数也不会允许在编译常量表达式中使用对象)

另一个例子是 std::variant 的提议:它有几乎所有的构造函数 constexpr 尽管析构函数有签名 ~variant() 而且它必须 call get<T_j> *this).T_j::~T_j() with j being index().

我错过了什么?

constexpr 构造函数可用于常量初始化,作为静态初始化的一种形式,保证在任何动态初始化发生之前发生。

例如,给定一个全局 std::mutex:

std::mutex mutex;

在一致的实现中(阅读:不是 MSVC),其他对象的构造函数可以安全地锁定和解锁 mutex,因为 std::mutex 的构造函数是 constexpr.