![](/img/trans.png)
[英]Why does a constexpr function behave differently for a reference?
[英]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.