我对constexpr功能感到困惑?

时间:2015-03-05 14:42:59

标签: c++ c++11 constexpr

在C ++ Primer,第5版,§6.5.2:

  

constexpr函数的定义与任何其他函数一样,但必须满足某些限制:返回类型和每个参数的类型必须是文字类型(§2.4.4, p.66),函数体必须只包含一个return语句

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

  

允许constexpr函数返回不是常量的值

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

这是一个矛盾的总结吗?我很困惑。
scale的返回类型是文字类型?
更新: 文字类型和常量之间有什么区别?

3 个答案:

答案 0 :(得分:8)

首先,我认为作者的意思是constexpr函数不必产生constant expression,这是可以在编译时进行评估的表达式。< / p>

如果函数的参数也是常量表达式,那么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不是一个恒定的表达。

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

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

答案 1 :(得分:6)

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

  

§7.1.5/ 7对constexpr函数的调用产生与...相同的结果   在所有方面调用等效的非constexpr函数   除了对constexpr函数的调用可以出现在常量中   表达

答案 2 :(得分:0)

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;