我对 constexpr 函数感到困惑?

I am confused about a constexpr function?

在 C++ Primer 中,第五版,§6.5.2:

A constexpr function is defined like any other function but must meet certain restrictions: The return type and the type of each parameter in must be a literal type (§2.4.4, p. 66), and the function body must contain exactly one return statement

但本章(第239页)中的另一句话:

A constexpr function is permitted to return a value that is not a constant

// scale(arg) is a constant expression if arg is a constant expression
constexpr size_t scale(size_t cnt) { return new_sz() * cnt; }

这是一个矛盾的总结吗?我对此感到困惑。
scale的return类型是文字类型?
更新: 文字类型和常量有什么区别?

constexpr 什么都不做,只是告诉编译器该值在编译时就存在,因此您可以将其用作模板参数(例如)

int a1 = 5;
std::array<int, a1> arr1; // error, a is variable

const int a2 = 5;
std::array<int, a2> arr2; // OK

int f1() { return 3; }
std::array<int, f1()> arr3; // error, compiler doesn't know it is const 3

constexpr int f2() { return 3; }
std::array<int, f2()> arr4; // OK

以后您还可以:

constexpr int f3() { return f1() + 1; } // error, f1 is not constexpr

constexpr int f4() { return f2() + 1; } // OK
std::array<int, f4()> arr5; // OK

现在关于文字类型限制:函数参数和结果类型应该是文字类型 (Need clarification on definition of literal type),与模板参数应用的限制完全相同(在编译类型中已知)。

constexpr std::string f5() { return "hello"; } // error, 
                   // std::string is not literal type

constexpr const std::string& f6() { 
  static const std::string s = "hello";
  return s;
}

template<const std::string& s> SomeClass { ... };
SomeClass<f6()> someObject;

这并不矛盾。除了强制 return 类型必须是 "literal type" 之外,标准草案还规定对 constexpr 函数的调用不必出现在常量表达式中。来自 C++11 标准草案:

§7.1.5/7 A call to a constexpr function produces the same result as a call to a equivalent non-constexpr function in all respects except that a call to a constexpr function can appear in a constant expression.

首先,我认为作者的意思是 constexpr 函数不必产生 constant expression,这是一个 可以 计算的表达式在编译时。

constexpr 函数只会产生一个 常量表达式 如果函数的参数也是 常量表达式 并且后面的注释说正是这样:

// scale(arg) is a constant expression if arg is a constant expression

紧随其后的示例也证明了这种行为:

int arr[scale(2)]; // ok: scale(2) is a constant expression
int i = 2; // i is not a constant expression
int a2[scale(i)]; // error: scale(i) is not a constant expression

在 C++ 中(相对于 C99)因为数组大小必须是一个 常量表达式 所以最后一种情况是一个错误因为scale 的参数不是常量表达式。

这与函数的 return 类型的概念不同,后者必须是 literal type,它是以下任何一种:

  • void(since c++14)(因此 constexpr 函数可以 return void)
  • 标量类型,包括算术类型、枚举类型、指针类型、指向成员类型的指针,std::nullptr_- t 和这些类型的 cv 限定版本)
  • 引用类型
  • 文字类型数组
  • class 具有以下所有属性的类型:
    • 有一个普通的析构函数,
      • 聚合类型
      • 一种至少有一个不是复制或移动构造函数的 constexpr(可能是模板)构造函数的类型
    • 所有非静态数据成员和基础 classes 都是非易失性文字类型。