为什么带有指针子对象的文字类类型的 constexpr 表达式不能是非类型模板参数
why a constexpr expression of literal class type with a pointer subobject can't be a non-type template argument
看了关于非类型模板参数的帖子后,我对那篇帖子中的一个例子感到困惑,我在这里引用了这个例子:
struct VariableLengthString {
const char *data_ = nullptr;
constexpr VariableLengthString(const char *p) : data_(p) {}
auto operator<=>(const VariableLengthString&) const = default;
};
template<VariableLengthString S>
int bar() {
static int i = 0;
return ++i;
}
int main() {
int x = bar<"hello">(); // ERROR
}
帖子说"相关措辞是[temp.arg.nontype]/2",所以我看了一下那个规则,它限制了什么可以是非类型模板参数。
非类型模板参数的模板参数应是模板参数类型的转换常量表达式。
所以,我看了一下converted constant expression
,它的定义在这里:
隐式转换为类型 T,其中转换后的表达式是常量表达式,隐式转换序列仅包含...
什么是常量表达式?这些规则在这里:
表达式 e 是核心常量表达式,除非 e 的计算遵循抽象机器的规则,将计算以下表达式之一:
(2.2( 对文字类的 constexpr 构造函数以外的函数的调用、constexpr函数或对普通析构函数的隐式调用。
那么,类类型VariableLengthString
文字类吗?是的,这是,有什么规则可以证明这里:
类型是文本类型,如果它是:
1. 可能符合 cv 条件的 void;或 2. 标量类型;或 3. 引用类型;或
4. 文本类型的数组;或
可能符合 CV 条件的类类型,具有以下所有属性:
- 它有一个微不足道的析构函数,
- 它要么是闭包类型,要么是聚合类型,要么至少有一个不是复制或移动构造函数的 constexpr 构造函数或构造函数模板(可能继承自基类(,
- 如果它不是联合,则其所有非静态数据成员和基类都是非易失性文本类型。
关键点是,这些类型的 ojbects 类型的子对象VariableLengthString
都是文字类型吗?类VariableLengthString
是否至少有一个 constexpr 构造函数?是的,他们是。由于这些规则:
类型、指向成员类型的指针([basic.compound](、std::nullptr_t 和这些类型的 cv 限定版本统称为标量类型。
所以,子对象data_
,它是指针类型,因此,它是标量类型,也是一个文字类型。子弹 3 满意。constexpr VariableLengthString(const char *p)
constexpr 构造函数吗?是的,确实如此,因为这些规则:
constexpr 构造函数的定义应满足以下要求:
- 该类不得有任何虚拟基类;
- 每个参数类型应为文本类型;
- 应初始化每个非变量非静态数据成员和基类子对象
对于constexpr VariableLengthString(const char *p)
来说,这三个规则都是满足的。综上所述,类VariableLengthString
是文字类型,类型VariableLengthString
的constexpr表达式可以作为非类型模板参数使用,因为它满足了作为转换常量表达式的要求。如果我错过了什么,请帮我找出来。
代码格式不正确,因为标准是这样说的:
对于引用或指针类型的非类型模板参数,或者对于类类型或其子对象的非类型模板参数中引用或指针类型的每个非静态数据成员,引用或指针值不得引用或分别是以下地址:
。
- 字符串文本
强调添加。C++17 及更早版本不允许将指向文本的指针(或引用(用作 NTTP。因此,C++20 不允许通过 NTTP 的类成员将指针(或引用(偷运到文本。
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 如何计算具有指定类型的表达式的相对精度和绝对精度
- 来自 DLL 的函数调用 [表观调用的括号前面的表达式必须具有(指向-)函数类型]
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 有没有办法一次声明相同类型的多个对象,并通过一个表达式立即使用相同的右值初始化它们?
- 表观调用前面的表达式必须具有指向 func 类型的指针
- 数组类型 int[n][n] 不可赋值,因为表达式必须具有常量值
- 正则表达式以匹配数字的重复模式,后跟任何类型的分隔符?
- C++ 编译错误:意外的类型名称"字符串":预期的表达式
- 表达式必须具有类类型 vs.
- 错误:表达式必须具有算术、无作用域枚举或带有运算符重载的指针类型
- 非类类型表达式的静态类型与动态类型之间的差异
- 如何确定涉及 C++ 中除法的算术表达式的数据类型
- 结构化绑定初始值设定项表单 { 赋值表达式 } 对于 clang 上的数组类型失败
- 下标需要数组或指针类型表达式必须具有指针对象类型
- 带有数组类型表达式的错误分配
- 表示函数参数的元组的类型表达式
- 如何确定撤销类型表达式的更大类型
- c++ 11中有新的函数类型表达式格式吗?