C++ 为什么这不是一个常量表达式?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24580714/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is this not a constant expression?
提问by Chris_F
In this trivial example, test2
fails to compile even though test1
succeeds, and I don't see why that is the case. If arr[i]
is suitable for a return value from a function marked constexpr
then why can it not be used as a non-type template argument?
在这个简单的例子中,test2
即使test1
成功也无法编译,我不明白为什么会这样。如果arr[i]
适用于标记的函数的返回值,constexpr
那么为什么不能将其用作非类型模板参数?
template<char c>
struct t
{
static const char value = c;
};
template <unsigned N>
constexpr char test1(const char (&arr)[N], unsigned i)
{
return arr[i];
}
template <unsigned N>
constexpr char test2(const char (&arr)[N], unsigned i)
{
return t<arr[i]>::value;
}
int main()
{
char a = test1("Test", 0); //Compiles OK
char b = test2("Test", 0); //error: non-type template argument
//is not a constant expression
}
Edit: This makes no difference:
编辑:这没有区别:
template<char c>
struct t
{
static const char value = c;
};
template <unsigned N>
constexpr char test1(const char (&arr)[N])
{
return arr[0];
}
template <unsigned N>
constexpr char test2(const char (&arr)[N])
{
return t<arr[0]>::value;
}
int main()
{
char a = test1("Test"); //Compiles OK
char b = test2("Test"); //error: non-type template argument
//is not a constant expression
}
回答by TemplateRex
Short answer: there are no constexpr
function parameters in C++11/14
.
简短的回答:有没有constexpr
在功能参数C++11/14
。
Longer answer: in test1()
, if i
is not a compile-time constant, the function is still usable at run-time. But in test2()
, it cannot be known to the compiler whether i
is a compile-time constant, and yet it is required for the function to compile.
更长的答案: in test1()
,如果i
不是编译时常量,则该函数在运行时仍然可用。但是在 中test2()
,编译器无法知道是否i
是编译时常量,但它是函数编译所必需的。
E.g. the following code for test1
will compile
例如下面的代码test1
将编译
int i = 0;
char a = test1("Test", i); // OK, runtime invocation of test1()
constexpr int i = 0;
constexpr char a = test1("Test", i); // also OK, compile time invocation of test1()
Let's simply your test2()
to
让我们简单test2()
地
constexpr char test3(unsigned i)
{
return t<i>::value;
}
This will not compile for test3(0)
because inside test3()
, it cannot be proven that i
is an unconditionalcompile-time expression. You would need constexpr
function parameters to be able to express that.
这不会编译 fortest3(0)
因为 inside test3()
,无法证明这i
是一个无条件编译时表达式。您需要constexpr
函数参数才能表达这一点。
Quote from the Standard
引用自标准
5.19 Constant expressions [expr.const]
5.19 常量表达式 [expr.const]
2 A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions:
— an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
— it is initialized with a constant expression or— it is a non-static data member of an object whose lifetime began within the evaluation of e;
2 条件表达式 e 是核心常量表达式,除非按照抽象机 (1.9) 的规则对 e 求值会求值以下表达式之一:
— 引用变量或引用类型数据成员的 id 表达式,除非该引用具有前面的初始化,并且
— 使用常量表达式初始化或——它是一个对象的非静态数据成员,其生命周期开始于 e 的计算;
This section has the following code example corresponding to your question:
本节有以下代码示例与您的问题相对应:
constexpr int f1(int k) {
constexpr int x = k; // error: x is not initialized by a
// constant expression because lifetime of k
// began outside the initializer of x
return x;
}
Because x
in the above example is not a constant expression, it means that you can't instantiate templates with either x
or k
inside f1
.
因为x
在上面的例子中不是一个常量表达式,这意味着你不能用x
或k
inside实例化模板f1
。
回答by Useless
There's a misconception of what constexpr
does here. It indicates that a function must be evaluatable at compile time for suitable arguments, but it does notremove the requirement still to compile in the general case.
对这里的作用存在误解constexpr
。它表明一个函数必须在编译时对合适的参数进行评估,但它并没有消除在一般情况下仍然编译的要求。
Let's take the first version:
我们来看第一个版本:
template <unsigned N>
constexpr char test1(const char (&arr)[N], unsigned i) {
return arr[i];
}
Now, this is clearly a compile-time evaluation:
现在,这显然是一个编译时评估:
enum { CompileTimeConstant = test1("Test", 0) };
your example maybe, but it's an optimizer/QoI issue:
您的示例可能是,但这是一个优化器/QoI 问题:
char MayBeCompileTimeConstant = test1("Test", 0);
and this example obviously isn't, but is still required to be evaluatable
这个例子显然不是,但仍然需要评估
char arr[10];
int i;
std::cin >> i;
std::cin >> arr;
char b = test1(arr, i);
std::cout << "'" << arr << "'[" << i << "] = " << b << '\n';
Since test2
can't possibly compile in for the last case, it can't compile at all. (Please note I'm not suggesting that code is good).
由于test2
无法为最后一种情况编译,因此根本无法编译。(请注意,我并不是在暗示代码是好的)。
回答by 101010
The problem here is that calling arr[i]
evokes the subscript operator operator[]
. This operator doesn't return a constant expression.
这里的问题是调用会调用arr[i]
下标操作符operator[]
。此运算符不返回常量表达式。
It's not a problem of constexpr
actually, is a problem of template argument deduction. A Non type template argument must be a constant expression which the return argument of subscript operator is not.
这不是constexpr
实际上的问题,是模板参数推导的问题。Non 类型模板参数必须是一个常量表达式,而下标运算符的返回参数不是。
Therefore, the compiler rightfully complains that arr[i]
is not a constant expression.
因此,编译器理所当然地抱怨这arr[i]
不是一个常量表达式。
回答by user1742529
Because arr[i]
is not compile-time constant expression. It can be different at run-time.
因为arr[i]
不是编译时常量表达式。它可以在运行时不同。