contexpr 函数返回的结构类型和类型之间的区别

Difference between structural type and type returned from contexpr function

我在玩 C++,被这个弄糊涂了:

cppreference.com says that a non-type template parameter must be a structural type and that a literal class type is an example of a structural type. Then it says that “Literal types are the types of constexpr variables and they can be constructed, manipulated, and returned from constexpr functions” (emphasis mine). (In fact constexpr 函数的 return 类型 必须 是文字类型。)

所以我的理解是可以从constexpr函数return编辑意味着是文字类型意味着是结构类型意味着可以用作非类型模板参数。

但似乎 std::optional 可以 return 从 constexpr 函数(下面的 bar)编辑,但是 不能 用作非类型模板参数(foo 紧接在下方)。怎么回事?

#include <optional>
template <std::optional<int> Z> int foo(int x) { return x; }
int main() { return foo<std::optional{0}>(0); }

这给出了编译器错误(GCC 和 clang resp.)

<source>:2:30: error: 'std::optional' is not a valid type for a template non-type parameter because it is not structural

<source>:2:30: error: type 'std::optional' of non-type template parameter is not a structural type

但是

#include <optional>
constexpr std::optional<int> bar() { return std::optional{0}; }
int main() { return *bar(); }

编译。

C++20 允许 classes 作为非类型模板参数 if they are:

a literal class type with the following properties:

  • all base classes and non-static data members are public and non-mutable and
  • the types of all base classes and non-static data members are structural types or (possibly multi-dimensional) array thereof.

std::optional 是文字 class 类型,但它具有非 public 数据成员,因此不允许作为非类型模板参数。

您可以创建自己的 optional-like class 只有 public 数据成员,然后它可以用作模板参数。