constexpr函数参数作为模板参数

Dan*_*nny 22 c++ constexpr c++11

我正在玩一些使用c ++ 11的玩具代码来弄清楚事情是如何运作的.在此期间,我遇到了以下问题,简化为:

template <int x, int y>
class add {
public:
    static constexpr int ret = x + y;
};

constexpr int addFunc(const int x, const int y) {
    return add<x,y>::ret;
}

int main() {
    const int x = 1;
    const int y = 2;
    cout << add<x,y>::ret << endl; // Works
    cout << addFunc(1,2) << endl;  // Compiler error
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我正在使用GCC 4.8.1并且输出为:
'x'不是模板参数中的常量表达式,用于'int'类型
'y'不是类型'int'的模板参数中的常量表达式

我试图计算的两种方式之间究竟有什么区别add::ret?这两个值都应该在编译时可用.

Ant*_*vin 10

如果你的目的只是缩短代码,在C++ 14中你可以创建变量模板:

template <int x, int y>
constexpr int addVar = x + y;

cout << addVar<5, 6> << endl; // Works with clang 3.5, fails on GCC 4.9.1
Run Code Online (Sandbox Code Playgroud)

GCC 5 也将支持这一点.


Rao*_*fen 10

你告诉编译器,这addFunc将是一个constexpr.但它依赖于参数,而不是constexpr本身,所以编译器已经扼杀了它.将它们标记为const仅表示您不会在函数体中修改它们,并且此时不会考虑对函数进行的特定调用.

有一种方法可以让编译器理解你只会将编译时常量传递给addFunc:将参数设置为模板参数本身:

template <int x, int y>
constexpr int addFunc() {
    return add<x,y>::ret;
}
Run Code Online (Sandbox Code Playgroud)

然后打电话给

cout << addFunc<1,2>() << endl;
Run Code Online (Sandbox Code Playgroud)


fja*_*sze 7

编译器不知道x和y在编译时是否始终可用作常量值(表达式),而且C++ 11/14不支持constexpr函数参数,因此x和y无法用作addFunc中模板add <>的参数.


Col*_*mbo 5

函数的函数参数constexpr不是常量表达式。该函数constexpr在外部(因为调用它可能会导致一个常量表达式),但内部的计算就像constexpr在普通函数中一样。

模板参数需要常量表达式。这些是代码中未满足的常量表达式的关键要求,因此会产生编译器错误([expr.const]/2,重点是我的):

条件表达式是一个核心常量表达式除非它涉及以下作为一个潜在的评价子表达式(3.2)中的一个[...]:

— 左值到右值的转换 (4.1) 除非它被应用于

  • 整数或枚举类型的泛左值,它引用具有前面初始化的非易失性 const 对象,用常量表达式初始化,
  • 文字类型的泛左值,它指代用constexpr 定义的非易失性对象,或指代此类对象的子对象,或
  • 文字类型的泛左值,指的是生命周期尚未结束的非易失性临时对象,用常量表达式初始化;

您正在对参数应用左值到右值的转换以将它们作为模板参数传递。
第一项不适用,因为函数参数既未事先初始化,也不知道用常量表达式初始化,第二项和第三项也不适用(特别是不应声明函数参数constexpr)。