非平凡类型的模板 class 析构函数

template class destructor for non-trivial types

我在玩 c++20 个概念

https://godbolt.org/z/931xaeY45

#include <type_traits>

template<typename T>
class Optional
{
public:
    ~Optional() requires (!std::is_trivially_destructible_v<T>);

};

#include <cstdio>
int main()
{
    const char* bool_value[] = {"false", "true"};
    
    bool is_trivial = std::is_trivial_v<Optional<int>>;
    bool is_trivial_destructable = std::is_trivially_destructible_v<Optional<int>>;
    
    std::printf("std::is_trivial_v<Optional<int>> = %s\n", bool_value[is_trivial]);
    std::printf("std::is_trivial_destructable<Optional<int>> = %s\n", bool_value[is_trivial_destructable]);
}

输出:

std::is_trivial_v<Optional<int>> = false
std::is_trivial_destructable<Optional<int>> = false

但是,我预计析构函数不会被实例化,因为对于这种情况,requires (false) 是为模板参数 int 生成的。

问: 为什么 ~Optional() requires (false) 使 class Optional 不平凡?

根据我的理解,您必须为具有 default (seems to work in GCC)[=15= 的普通可破坏类型 T 提供 替代方案]

template<typename T>
class Optional {
public:
  // Chosen for not trivially destructible types
  ~Optional() requires (not std::is_trivially_destructible_v<T>);
  // Chosen for everything else (trivially destructible types)
  ~Optional() = default;
};

在你的情况下,只有一个未设置为 default 的选项,这使得它默认不可破坏。

我对标准的阅读 and MSVC 说这是一个编译错误。

在 C++20 中,这个:

~Optional() requires (!std::is_trivially_destructible_v<T>);

是一个“预期的析构函数”。它可能会或可能不会成为基于一系列规则的实际析构函数。但真正重要的是 this rule:

If a class has no user-declared prospective destructor, a prospective destructor is implicitly declared as defaulted ([dcl.fct.def]).

您的class一个“用户声明的预期析构函数”。因此,没有“隐式声明为默认”构造函数 ever.

这很重要,因为 this rule kicks in:

At the end of the definition of a class, overload resolution is performed among the prospective destructors declared in that class with an empty argument list to select the destructor for the class, also known as the selected destructor. The program is ill-formed if overload resolution fails.

因为 T 是微不足道的可破坏的,所以重载决议不能调用你预期的析构函数,因为 requires 约束会杀死它。并且找不到其他析构函数。所以它不应该编译,GCC 可能还没有正确地实现规则。

无论如何,您需要提供默认的替代析构函数:

~Optional() requires (!std::is_trivially_destructible_v<T>);
~Optional() = default;