簡體   English   中英

clang和gcc中的Constexpr復合賦值運算符

[英]Constexpr compound assignment operator in clang and gcc

我有以下代碼:

main.cpp中

#include <cstdint>
#include <type_traits>

enum class FooEnum : uint8_t{
    Foo1 = 0, 
    Foo2 = 1
};

constexpr uint32_t& operator|= (uint32_t& lhs, FooEnum rhs) {
    return lhs |= 1u << static_cast<uint8_t>(rhs);
}

int main() {
    uint32_t bar{0};
    bar|=FooEnum::Foo1;
}

基本上, |=運算符應該采用枚舉並設置位,其位置對應於其整數值。

在fedora 21上用clang ++ 3.5.0編譯時,一切正常,但是當用g ++ 4.9.2編譯時,它會拋出一個錯誤,說這不是一個常量表達式

main.cpp: In function ‘constexpr uint32_t& operator|=(uint32_t&, FooEnum)’:
main.cpp:16:2: error: expression ‘(lhs = (lhs | (1u << ((int)rhs))))’ is not a constant-expression
  }
  ^

這適用於所有類型的編譯器標志組合,但您可以使用g++ -std=c++11 -o a.out main.cpp (c ++ 14沒有區別)

所以我的問題是:

  1. 哪個編譯器是正確的(以及為什么)?
  2. 有沒有辦法實現operator|=這樣g ++會接受它作為constexpr

編輯:
如果您想知道,為什么我首先嘗試將運算符聲明為constexpr ,盡管在示例中不需要:
在我的實際代碼中,我使用|= -operator來實現(constexpr) | -operator,我想在constexpr表達式中使用,但在此之前,我偶然發現了兩個編譯器之間的區別,沒有意識到,gcc4.9並不完全支持c ++ 14(但是接受-std=c++14 flag)。
當使用運算符實際初始化一個全局constexpr變量時,即使clang只用c ++ 14標志編譯它。

表達式lhs |= 1u << static_cast<uint8_t>(rhs)本身永遠不能是一個常量表達式 ,因為它修改了lhs 禁止在C ++ 14中使用的規則是§5.19/ 2.15(在C ++ 11中也存在有效的等效規則):

條件表達式 e核心常量表達式,除非根據抽象機器(1.9)的規則評估e將評估以下表達式之一:

  • 修改對象(5.17,5.2.6,5.3.2), 除非它應用於文字類型的非易失性左值,該文字類型引用一個非易失性對象,其生命周期始於e的評估范圍內 ;

在C ++ 11中,由於§7.1.5/ 5,它必須是一個:

對於constexpr函數,如果不存在函數參數值,使得函數調用替換將產生常量表達式(5.19),則程序格式錯誤; 無需診斷。

在調用替換之后,不存在使返回的表達式成為常量表達式的參數:賦值可以防止這種情況發生。 因此,程序在C ++ 11中-std=c++11不正確(但不需要診斷),並且在使用-std=c++11編譯時,GCC顯示符合規范的行為。
在C ++ 14中,該規則已經過調整:

對於非模板,非默認的constexpr函數[...],如果不存在參數值,使得函數[...]的調用可以是核心常量表達式(5.19)的計算子表達式 ,則程序格式錯誤; 無需診斷。

這使得返回表達式本身成為非常量表達式,只要該函數可以在另一個核心常量表達式中進行求值,例如從另一個constexpr函數中:

constexpr auto foo(FooEnum rhs)
{
    uint32_t x = 0;
    x |= rhs;
    return x;
}

foo(FooEnum::Foo1)是核心常量表達式,因此可以在核心常量表達式中調用operator|= ,因此函數定義格式正確。

正如評論中的@dyp所述,GCC僅支持自版本5以來的“對constexpr函數的放寬約束”特性.GCC 5.1編譯代碼

所以現在constexpr函數的主體通常由不是常量表達式的語句組成。 第一個引用部分之后的示例顯示了一個函數incr ,GCC也會拒絕該函數:

 constexpr int incr(int &n) { return ++n; } constexpr int h(int k) { int x = incr(k); // OK: incr(k) is not required to be a core // constant expression return x; } 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM