c++ - 为什么带有指针子对象的文字类类型的constexpr表达式不能是非类型模板参数

标签 c++ language-lawyer c++20

看完有关非类型模板参数的the帖子后,我对该帖子中的示例感到困惑,在此引用示例:

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”,所以我看了一下这个规则,它限制了什么可以是非类型模板参数。

A template-argument for a non-type template-parameter shall be a converted constant expression of the type of the template-parameter.



所以,我看了一下converted constant expression,它的定义在这里:

A converted constant expression of type T is an expression, implicitly converted to type T, where the converted expression is a constant expression and the implicit conversion sequence contains only...



什么是常数表达式?这些规则在这里:

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

(2.2) an invocation of a function other than a constexpr constructor for a literal class, a constexpr function, or an implicit invocation of a trivial destructor.



那么,类类型VariableLengthString是一个文字类吗?是的,可以在这里证明哪些规则:

A type is a literal type if it is:
1. possibly cv-qualified void; or
2. a scalar type; or
3. a reference type; or
4. an array of literal type; or
a possibly cv-qualified class type that has all of the following properties:

  1. it has a trivial destructor,
  2. it is either a closure type, an aggregate type, or has at least one constexpr constructor or constructor template (possibly inherited from a base class) that is not a copy or move constructor,
  3. if it is not a union, all of its non-static data members and base classes are of non-volatile literal types.


关键是,这些类型为VariableLengthString的对象的子对象是否都是文字类型? VariableLengthString类是否至少有一个constexpr构造函数?是的,因为这些规则:

Arithmetic types, enumeration types, pointer types, pointer to member types ([basic.compound]), std​::​nullptr_­t, and cv-qualified versions of these types are collectively called scalar types.



因此,子对象data_是指针类型。因此,它是标量类型,也是文字类型。满足子弹3。constexpr VariableLengthString(const char *p)是否是constexpr构造函数?是的,因为这些规则是:

The definition of a constexpr constructor shall satisfy the following requirements:

  1. the class shall not have any virtual base classes;
  2. each of the parameter types shall be a literal type;
  3. every non-variant non-static data member and base class subobject shall be initialized


对于constexpr VariableLengthString(const char *p),这三个规则都得到满足。总之,VariableLengthString类是文字类型,并且VariableLengthString类型的constexpr表达式可以用作非类型模板参数,因为它满足为转换后的常量的要求。表达式。为什么上面的代码格式错误?如果我错过了什么,请帮助我找出它们。

最佳答案

代码格式错误,因为the standard says so:

For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):

... * a string literal



表达式是否为常量表达式并不重要。您不能将指向字符串文字的指针用作非类型模板参数(NTTP)。而且,将用户定义类型作为NTTP的建议不会对此进行更改,因此您不能在NTTP中隐藏指向字符串文字的指针,并且仍然希望它能够正常工作。

关于c++ - 为什么带有指针子对象的文字类类型的constexpr表达式不能是非类型模板参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61838757/

相关文章:

c++ - 使用带有 `make check` 的 Boost 单元测试框架 (UTF)

c++ - 类无法访问其自己的私有(private)静态 constexpr 方法 - Clang 错误?

c++ - 用于constexpr函数中的constexpr

c++ - 为什么 std::isnan 不是 constexpr?

c++ - 检测函数类型是否为 noexcept 的特征

c++ - 最准确,但是 "cheapest"测量 C++ 代码的方法?

c++ - 如何在 Windows 下配置文件?

c++ - 如何使用 ms code gen 添加/bigobj 切换到 clang?

使用 memcmp 比较两个字符串文字

C++ 算法堆分配保证