我正在玩一些使用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;
}
我正在使用GCC 4.8.1,输出是:
'x'不是类型'int'的模板参数中的常量表达式
'y'不是类型'int'
我尝试计算add::ret
的两种方式之间究竟有什么区别?这两个值都应该在编译时可用。
答案 0 :(得分: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
GCC 5 will also support this。
答案 1 :(得分:10)
你告诉编译器,addFunc
将是一个constexpr。但它依赖于参数,而不是constexpr本身,所以编译器已经扼杀了它。将它们标记为const仅表示您不会在函数体中修改它们,并且此时不会考虑对函数进行的特定调用。
有一种方法可以让编译器理解你只是将编译时常量传递给addFunc
:使参数本身成为模板参数:
template <int x, int y>
constexpr int addFunc() {
return add<x,y>::ret;
}
然后打电话给
cout << addFunc<1,2>() << endl;
答案 2 :(得分:7)
编译器不知道x和y在编译时是否始终可用作常量值(表达式),而且 C ++ 11/14不支持constexpr函数参数,所以x和y无法用作模板add&lt;&gt;的参数。在addFunc。
答案 3 :(得分:4)
constexpr
函数的函数参数不是常量表达式。该函数向外constexpr
(因为调用它可能会导致常量表达式),但内部计算与正常函数中的constexpr
一样。
Template-arguments需要常量表达式。这些是代码中不满足的常量表达式的关键要求,从而产生编译器错误([expr.const] / 2,强调我的):
条件表达式是核心常量表达式,除非它 涉及以下之一作为潜在评估的子表达式 (3.2)[...]:
- 左值 - 右值转换(4.1),除非它适用于
- 一个整数或枚举类型的glvalue,它引用一个带有前面初始化的非易失性const对象,已初始化 使用常量表达式或
- 一个文字类型的glvalue,它指的是用constexpr 定义的非易失性对象,或者指的是这样的子对象 对象,或
- 一个文字类型的glvalue,指的是一个非易失性临时对象,其生命周期尚未结束,用一个常量初始化 表达
您正在对参数应用左值到右值转换,以将它们作为模板参数传递。
第一个项目不适用,因为函数参数既没有先前初始化也不知道用常量表达式初始化,第二个和第三个项目也没有(特别是函数参数应该是不要声明constexpr
)。