2016-02-26 82 views
5

考慮下面的代碼available on gcc.godbolt.org使用在非`constexpr`上下文`constexpr`功能的λ:鐺VS GCC

template <typename TF> 
constexpr auto fn_x(TF f) 
{ 
    return f(); 
} 

constexpr auto get_x() 
{ 
    return fn_x([]{ return 0; }); 
} 

int main() 
{ 
    auto res = get_x(); 
} 

它編譯下克++ 5.3.x和更新的(包括g ++ 6.xx

它不會下鐺++ 3.7.x並用以下錯誤較新的編譯:

error: constexpr function never produces a constant expression [-Winvalid-constexpr] 
constexpr auto get_x() 
      ^
note: subexpression not valid in a constant expression 
     return fn_x([]{ return 0; });       

的可能解決方案,以使代碼編譯GCC和鐺使用「間接層」與decltype,也擺脫在定義lambda的函數constexprgcc.godbolt.org link

根據標準哪個編譯器在這裏是正確的?

+0

無論如何,也許與你的問題更相關:做任何你測試的編譯器聲明'get_x()'可以用在一個常量表達式中?如果不是,你的問題是「我允許將'constexpr'添加到永遠不能用於常量表達式的函數嗎?」 – hvd

+0

@hvd:關於分號,我總是用'-Wpedantic'編譯真實的代碼,這會告訴我這個錯誤。我習慣於編寫lambda-heavy代碼('auto l = [] {...};'),所以有時我的大腦會在函數結尾自動添加分號。 –

+0

@hvd它是有效的C++ 11 - ';'是一個*空聲明*。參見[CWG 569](http://wg21.link/cwg569)。 –

回答

6

這兩個編譯器都認爲get_x()不能用於常量表達式。您可以通過將auto res = get_x();更改爲constexpr auto res = get_x();來告知,其中GCC將平等拒絕它。

至於在函數定義時間等鐺檢測它,而不是在功能等的gcc使用確實,兩者都允許:(重點煤礦)

7.1.5 The constexpr specifier [dcl.constexpr]

5 For a non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting constexpr constructor, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression (5.19), the program is ill-formed; no diagnostic required. [...]

它是在一般情況下,以可靠地檢測是否不可能存在允許將結果用於常量表達式的函數調用,這就是爲什麼診斷是可選的。

+0

我很羞辱! :) – SergeyA

+1

另一方面,缺乏lambda的'constexpr'支持在C++中有一點缺失。 [這裏](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4487.pdf)就是這樣一個建議。 – Yakk