簡體   English   中英

為什么引用上的 constexpr 函數不是 constexpr?

[英]Why is a constexpr function on a reference not constexpr?

考慮以下函數:

template <size_t S1, size_t S2>
auto concatenate(std::array<uint8_t, S1> &data1, std::array<uint8_t, S2> &data2) {
    std::array<uint8_t, data1.size() + data2.size()> result;

    auto iter = std::copy(data1.begin(), data1.end(), result.begin());
    std::copy(data2.begin(), data2.end(), iter);

    return result;
}

int main()
{
    std::array<uint8_t, 1> data1{ 0x00 };
    std::array<uint8_t, 1> data2{ 0xFF };

    auto result = concatenate(data1, data2);
    return 0;
}

當使用clang 6.0編譯時,使用-std=c++17,這個函數不會編譯,因為數組上的size成員函數不是constexpr,因為它是一個引用。 錯誤信息是這樣的:

錯誤:非類型模板參數不是常量表達式

當參數不是引用時,代碼按預期工作。

我想知道為什么會這樣,因為 size() 實際上返回一個模板參數,它幾乎不可能是 const 了。 參數是否是引用應該沒有區別。

我知道我當然可以使用 S1 和 S2 模板參數,該函數只是問題的一個簡短說明。

標准中有什么嗎? 我很驚訝從中得到一個編譯錯誤。

因為你已經評估了一個參考。 來自[expr.const]/4

表達式 e 是核心常量表達式,除非按照抽象機器的規則對 e 求值會求值以下表達式之一:

  • ...
  • 引用變量或引用類型數據成員的id 表達式,除非該引用具有前面的初始化並且
    • 它可用於常量表達式或
    • 它的生命周期開始於 e 的計算;
  • ...

您的引用參數沒有前面的初始化,因此不能在常量表達式中使用。

您可以在這里簡單地使用S1 + S2

關於此問題,已報告了一個關於 clang 的錯誤,標題為: Clang 不允許在非類型模板參數中使用 constexpr 類型轉換

其中的討論指出這並不是真正的錯誤。

表達式 e 是核心常量表達式,除非按照抽象機器的規則對 e 求值會求值以下表達式之一:

  • [...]
  • 引用變量或引用類型數據成員的 id 表達式,除非該引用具有前面的初始化並且
    • 它用常量表達式初始化或
    • 它的生命周期開始於 e 的計算;
  • [...]

以上引文來自 n4659 草案的 [expr.const]/2.11,並添加了重點。

不幸的是,標准規定在類成員訪問表達式中對點或箭頭前的后綴表達式求值; 63 [expr.ref]/1 后綴表達式是a in ab 這篇筆記真的很有趣,因為這里正是這種情況:

63) 如果對類成員訪問表達式求值,即使結果不需要確定整個后綴表達式的值,例如如果 id-expression 表示靜態成員,也會發生子表達式求值。

因此,即使data不是必需的,也會對data進行評估,並且常量表達式規則也適用於它。

暫無
暫無

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

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