lambda'da static_assert ile constexpr varsa, hangi derleyici doğrudur?


13

Biz kullanmak istediğinizde static_assertbir de if constexprbazı şablon parametresine durum bağımlı yapmak zorundadır. İlginç bir şekilde, gcc ve clang, kod bir lambda içine sarıldığında katılmıyor.

Aşağıdaki kod gcc ile derlenir, ancak clang if constexprdoğru olamazsa bile iddiayı tetikler .

#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>();
}

Burada canlı örnek .

Kolayca ikame ile tespit edilebilir False<T>ile False<decltype(x)>.

Soru şu: hangi derleyici doğru? Ben gcc doğru olduğunu varsayalım çünkü içinde koşul static_assertbağlıdır T, ama emin değilim.


Bu aynı soruyu sorar ancak ters yönden gelir: stackoverflow.com/questions/59393908/… .
NathanOliver

1
@mfnx Çoğaltılamıyor . Bir örnek paylaşabilir misiniz?
NathanOliver

2
: I (ill NDR kurdu) hem haklı söyleyebilirim static_assert(False<int>, "AAA");eşdeğerdir static_assert(false, "AAA");lambda iç.
Jarod42

2
@mfnx Sabitin değerini değiştirdiniz. f(std::integral_constant<int, 1>{});Sabitin Wandbox olduğu OP örneğini kullanmak iddiayı tetiklemez: wandbox.org/permlink/UFYAmYwtt1ptsndr
NathanOliver

1
@NathanOliver Evet haklısın, gürültü için üzgünüm. Gcc doğru görünüyorsa, constexpr'deki kod>> 0 sabiti ise atılmalıdır;
mfnx

Yanıtlar:


1

Kaynaktan [stmt.if] / 2 (vurgu benim)

İf ifadesinin constexpr biçiminde olması durumunda, koşulun değeri, bağlamsal olarak dönüştürülmüş, bool türünde sabit bir ifade olacaktır; bu forma constexpr if ifadesi denir. Dönüştürülen koşulun değeri yanlışsa, ilk alt öğe atılan bir deyimdir, aksi takdirde varsa ikinci alt öğe, atılan bir deyimdir. Çevreleyen şablonlanmış bir varlığın ([temp.pre]) somutlaştırılması sırasında, koşul somutlaştırılmasından sonra değere bağlı değilse, atılan alt tabaka (eğer varsa) somutlaştırılmaz.

Statik iddianın düşeceğini düşündüğünü okumak, ancak durum böyle değildir.

Statik iddia şablonun ilk aşamasında tetiklenir çünkü derleyici her zaman yanlış olduğunu bilir.

Kaynaktan [temp.res] / 8 (vurgu benim)

Bir şablonun geçerliliği, herhangi bir somutlaştırmadan önce kontrol edilebilir. [ Not: Hangi adların tür adları olduğunu bilmek, her şablonun sözdiziminin bu şekilde kontrol edilmesini sağlar. - son not ] Program kötü biçimlendirilmiştir, aşağıdaki durumlarda teşhis gerekmez:

  • (8.1) bir şablon içindeki deyim veya şablon somutlaştırılmamışsa , şablon veya bir constexpr alt öğesi için geçerli bir uzmanlık oluşturulamaz veya

[...]

Evet, aslında, False<T>bağlıdır T. Sorun, genel bir lambda'nın kendisinin bir şablon False<T>olması ve lambda'nın herhangi bir şablon parametresine bağlı olmamasıdır.

Bir İçin Tbu False<T>yanlıştır, statik assert hep yanlış olacak olursa olsun hangi şablon argümanı lambda gönderilir.

Derleyici, şablonun herhangi bir örneği operator()için statik onaylayıcının daima geçerli T'yi tetikleyeceğini görebilir. Bu nedenle derleyici hatası.

Bunun için bir çözüm aşağıdakilere bağlı olacaktır 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>{});
}

Canlı örnek


13

Buradaki olağan kural [temp.res] / 8'dir :

Program kötü biçimlendirilmiş, tanı koymaya gerek yok, eğer: bir şablon için geçerli bir uzmanlık oluşturulamaz veya bir şablon içindeki deyim ve şablon somutlaştırılmamışsa bir constexpr ifadesi oluşturulamaz

Bir kez başlattığınızda foo<T>, static_assertsahip olduğunuz artık bağımlı değildir. Bu olur static_assert(false)- jenerik lambda'nın çağrı operatörünün olası tüm örnekleri için f. Bu yanlış biçimlendirilmiş, teşhis gerektirmez. Clang teşhis eder, gcc yapmaz. İkisi de doğru.

O önemli olmadığını Not static_assertburada olduğunu atılır.

Kolayca ikame ile tespit edilebilir False<T>ile False<decltype(x)>.

Bu static_assert, jenerik lambda içinde bağımlılığı korur ve şimdi varsayımsal olarak geçerli bir uzmanlaşma olabileceği bir duruma giriyoruz, bu yüzden artık kötü şekillenmiş değiliz, ndr.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.