簡體   English   中英

如果 lambda 中帶有 static_assert 的 constexpr,哪個編譯器是正確的?

[英]if constexpr with static_assert in lambda, which compiler is correct?

當我們想在if constexpr使用static_assert ,我們必須使條件依賴於某個模板參數。 有趣的是,當代碼包含在 lambda 中時,gcc 和 clang 不同意。

以下代碼使用 gcc 進行編譯,但 clang 會觸發斷言,即使if constexpr不能為真。

#include <utility>

template<typename T> constexpr std::false_type False;

template<typename T>
void foo() {

    auto f = [](auto x) {
        constexpr int val = decltype(x)::value;
        if constexpr(val < 0) {
            static_assert(False<T>, "AAA");
        }
    };

    f(std::integral_constant<int, 1>{});
}

int main() {
    foo<int>();
}

現場示例在這里

通過將False<T>替換為False<decltype(x)>可以輕松修復它。

所以問題是:哪個編譯器是正確的? 我認為 gcc 是正確的,因為static_assert的條件取決於T ,但我不確定。

這里通常的規則是[temp.res]/8

程序格式錯誤,無需診斷,如果: 不能為模板或 constexpr 的子語句生成有效的特化 模板中的 if 語句且模板未實例化

實例化foo<T> ,您擁有的static_assert不再依賴。 它變為static_assert(false) - 對於泛型 lambda f的調用運算符的所有可能實例化。 這是格式錯誤的,不需要診斷。 Clang 診斷,gcc 沒有。 兩者都是正確的。

請注意,這里的static_assert丟棄並不重要。

通過將False<T>替換為False<decltype(x)>可以輕松修復它。

這使static_assert依賴於泛型 lambda,現在我們進入一種狀態,假設可能存在有效的特化,因此我們不再是格式錯誤的,ndr。

來自[stmt.if]/2 (強調我的)

如果 if 語句的形式為 if constexpr,則條件的值應為上下文轉換的 bool 類型常量表達式; 這種形式稱為 constexpr if 語句。 如果轉換條件的值為假,則第一個子語句是丟棄的語句,否則第二個子語句(如果存在)是丟棄的語句。 在封閉模板化實體 ([temp.pre]) 的實例化期間,如果條件在實例化后不依賴於值,則不會實例化丟棄的子語句(如果有)。

讀到人們會認為靜態斷言會被刪除,但事實並非如此。

靜態斷言在模板的第一階段被觸發,因為編譯器知道它總是假的。

來自[temp.res]/8 (強調我的)

可以在任何實例化之前檢查模板的有效性。 [注意:知道哪些名稱是類型名稱允許以這種方式檢查每個模板的語法。 尾注] 程序格式錯誤,無需診斷,如果:

  • (8.1) 不能為模板模板內的 constexpr if 語句的子語句生成有效的特並且模板沒有被實例化,或者

[...]

是的,您的False<T>取決於T 問題在於泛型 lambda 本身就是一個模板,並且False<T>不依賴於 lambda 的任何模板參數。

對於一個T的是False<T>是假的,靜態斷言永遠是假的,無論哪個模板參數發送到拉姆達。

編譯器可以看到,對於模板operator()任何實例化,靜態斷言將始終為當前 T 觸發。因此編譯器錯誤。

對此的解決方案是依賴於x

template<typename T>
void foo() {

    auto f = [](auto x) {
        if constexpr(x < 0) {
            static_assert(False<decltype(x)>, "AAA");
        }
    };

    f(std::integral_constant<int, 1>{});
}

活生生的例子

暫無
暫無

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

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