[英]constexpr expression and variable lifetime, an example where g++ and clang disagree
Consider the simple C++11 code: 考虑一下简单的C ++ 11代码:
template<int N>
struct Foo {};
template <int N>
constexpr int size(const Foo<N>&) { return N; }
template <int N>
void use_size(const Foo<N>& foo) { constexpr int n = size(foo); }
int main()
{
Foo<5> foo;
constexpr int x = size(foo); // works with gcc and clang
// _but_
use_size(foo); // the same statement in the use_size()
// function _only_ works for gcc
}
I can successfuly compile it with g++ -std=c++11 foo.cpp
我可以用
g++ -std=c++11 foo.cpp
成功编译它
however if I use clang++, clang++ -std=c++11 foo.cpp
I get 但是,如果我使用clang ++,
clang++ -std=c++11 foo.cpp
我得到了
foo.cpp:15:28: error: constexpr variable 'n' must be initialized by a constant expression
void use_size(const Foo<N>& foo) { constexpr int n = size(foo); }
~~~~~^~~~
foo.cpp:23:5: note: in instantiation of function template specialization 'use_size<5>' requested here
use_size(foo); // the same statement in the use_size()
^
1 error generated.
(nb: compiler versions. I have checked the previous statement with g++ version 5.3.1 and 7.2.1 and with clang++ version 3.6.2 and 5.0.0) (nb:编译器版本。我用g ++版本5.3.1和7.2.1以及clang ++版本3.6.2和5.0.0检查了前一个语句)
My question: which of g++ or clang is right? 我的问题: g ++或clang中哪一个是对的? What is the problem?
问题是什么?
My interpretation is that clang++ is right and g++ is too permissive . 我的解释是clang ++是对的,而g ++太宽容了 。
We can find a close example ([expr.const] section, page 126) in the standard https://isocpp.org/std/the-standard (draft can be downloaded, attention big PDF! ). 我们可以在标准https://isocpp.org/std/the-standard中找到一个接近的例子([expr.const]部分,第126页)(可以下载草稿, 注意大PDF! )。
constexpr int g(int k) {
constexpr int x = incr(k);
return x;
}
where it is explained that: 在那里解释说:
error: incr(k) is not a core constant expression because lifetime of k began outside the expression incr(k)
错误:incr(k)不是核心常量表达式,因为k的生命周期开始于表达式incr(k)之外
This is exactly what is happening in the use_size()
function with the foo
argument, even if the size()
function only use the N
template parameter. 这正是带有
foo
参数的use_size()
函数中发生的情况,即使size()
函数仅使用N
模板参数。
template <int N>
constexpr int size(const Foo<N>&) { return N; }
template <int N>
void use_size(const Foo<N>& foo) { constexpr int n = size(foo); }
I was expecting Clang to be wrong in this case. 在这种情况下,我期待Clang出错。 It should evaluate your function call as being a constant expression, simply because you use only the template parameter, and not the object itself.
它应该将您的函数调用评估为一个常量表达式,因为您只使用模板参数,而不是对象本身。 Since you don't use the object in your
constexpr
function, there should be nothing prohibit compile time evaluation. 由于您没有在
constexpr
函数中使用该对象,因此不应该禁止编译时评估。
However, there's a rule in the standard that says object that began their lifetime preceding the constant expression such as a reference is not useable as constexpr. 但是,标准中有一条规则,即在常量表达式(例如引用)之前开始其生命周期的对象不能用作constexpr。
There is a simple fix in that case. 在这种情况下有一个简单的解决方案。 I think it didn't like the reference:
我认为它不喜欢参考:
template <int N> // pass by value, clang is happy
void use_size(Foo<N> foo) { constexpr int n = size(foo); }
Here's a live example 这是一个实例
Alternatively, you can also copy your foo object and use that local object: 或者,您也可以复制您的foo对象并使用该本地对象:
template <int N>
void use_size(const Foo<N>& foo) {
auto f = foo;
constexpr int n = size(f);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.