我已将constexpr函数定义如下:
constexpr int foo(int i)
{
return i*2;
}
这就是主要功能:
int main()
{
int i = 2;
cout << foo(i) << endl;
int arr[foo(i)];
for (int j = 0; j < foo(i); j++)
arr[j] = j;
for (int j = 0; j < foo(i); j++)
cout << arr[j] << " ";
cout << endl;
return 0;
}
该程序是在OS X 10.8下使用命令clang ++编译的。我很惊讶编译器没有产生关于foo(i)不是常量表达式的任何错误消息,并且编译的程序实际上工作正常。为什么呢?
答案 0 :(得分:21)
C ++中constexpr
函数的定义使得函数保证能够在调用时生成常量表达式,以便在评估中仅使用常量表达式。但是,如果未在constexpr
中使用结果,则评估是在编译时还是在运行时进行(请参阅this answer)。将非常量表达式传递给constexpr
时,可能无法获得常量表达式。
但是,您的上述代码不应该编译,因为i
不是foo()
明确用于生成结果的常量表达式,然后将其用作数组维度。似乎clang实现了C风格的可变长度数组,因为它为我产生了以下警告:
warning: variable length arrays are a C99 feature [-Wvla-extension]
更好的测试,看看某些东西是否确实是一个常量表达式,是用它来初始化constexpr
的值,例如:
constexpr int j = foo(i);
答案 1 :(得分:1)
我使用了顶部的代码(添加了“using namespace std;”)并且在使用“g ++ -std = c ++ 11 code.cc”进行编译时没有错误(请参阅下面的参考资料,以确定是否符合此条件)代码)这是代码和输出:
#include <iostream>
using namespace std;
constexpr int foo(int i)
{
return i*2;
}
int main()
{
int i = 2;
cout << foo(i) << endl;
int arr[foo(i)];
for (int j = 0; j < foo(i); j++)
arr[j] = j;
for (int j = 0; j < foo(i); j++)
cout << arr[j] << " ";
cout << endl;
return 0;
}
output:
4
0 1 2 3
现在考虑引用https://msdn.microsoft.com/en-us/library/dn956974.aspx它声明:“... constexpr函数是一个在返回值可以在编译时消耗代码需要它的函数。一个constexpr函数必须接受并只返回文字类型。参数是constexpr值,消费代码需要在编译时返回值,例如初始化constexpr变量或提供非类型模板参数,它产生编译时常量。当使用非constexpr参数调用时,或者当它在编译时不需要它的值,它在运行时产生一个像常规函数一样的值。(这种双重行为使你不必编写相同函数的constexpr和non-constexpr版本。 )“
它给出了有效的例子:
constexpr float exp(float x, int n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp(x * x, n / 2) :
exp(x * x, (n - 1) / 2) * x;
}
答案 2 :(得分:0)
这是一个老问题,但它是谷歌搜索VS错误消息的第一个结果&#34; constexpr函数返回是非常数&#34;。虽然它对我的情况没有帮助,但我以为我把我的两分钱放进......
尽管Dietmar给出了constexpr的一个很好的解释,虽然错误应该立即被捕获(就像-pedantic标志一样) - 这段代码看起来像是在进行一些编译器优化。
值i被设置为2,并且在程序的持续时间中我永远不会改变。编译器可能注意到这一点,并将变量优化为常量(在将该参数应用到函数之前,只将所有对变量i的引用替换为常量2 ...),从而创建对foo()的constexpr调用。
我敢打赌,如果你查看反汇编,你会看到对foo(i)的调用被替换为常量值4 - 因为这是在执行该函数期间调用此函数的唯一可能的返回值。程序
使用-pedantic标志强制编译器从最严格的角度分析程序(可能在任何优化之前完成),从而捕获错误。