[英]constexpr expression and variable lifetime, an example where g++ and clang disagree
考慮一下簡單的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
}
我可以用g++ -std=c++11 foo.cpp
成功編譯它
但是,如果我使用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:編譯器版本。我用g ++版本5.3.1和7.2.1以及clang ++版本3.6.2和5.0.0檢查了前一個語句)
我的問題: g ++或clang中哪一個是對的? 問題是什么?
我的解釋是clang ++是對的,而g ++太寬容了 。
我們可以在標准https://isocpp.org/std/the-standard中找到一個接近的例子([expr.const]部分,第126頁)(可以下載草稿, 注意大PDF! )。
constexpr int g(int k) {
constexpr int x = incr(k);
return x;
}
在那里解釋說:
錯誤:incr(k)不是核心常量表達式,因為k的生命周期開始於表達式incr(k)之外
這正是帶有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); }
在這種情況下,我期待Clang出錯。 它應該將您的函數調用評估為一個常量表達式,因為您只使用模板參數,而不是對象本身。 由於您沒有在constexpr
函數中使用該對象,因此不應該禁止編譯時評估。
但是,標准中有一條規則,即在常量表達式(例如引用)之前開始其生命周期的對象不能用作constexpr。
在這種情況下有一個簡單的解決方案。 我認為它不喜歡參考:
template <int N> // pass by value, clang is happy
void use_size(Foo<N> foo) { constexpr int n = size(foo); }
這是一個實例
或者,您也可以復制您的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.