Ketika kita ingin menggunakan static_assert
dalam if constexpr
kita harus membuat kondisi tergantung pada beberapa parameter template. Menariknya, gcc dan dentang tidak setuju ketika kode tersebut dibungkus dengan lambda.
Kode berikut dikompilasi dengan gcc, tetapi dentang memicu pernyataan, bahkan jika itu if constexpr
tidak benar.
#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>();
}
Itu dapat dengan mudah diperbaiki dengan mengganti False<T>
dengan False<decltype(x)>
.
Jadi pertanyaannya adalah: kompiler mana yang benar? Saya berasumsi bahwa gcc benar karena kondisi di static_assert
tergantung pada T
, tetapi saya tidak yakin.
c++
templates
language-lawyer
c++17
static-assert
penghijauan
sumber
sumber
static_assert(False<int>, "AAA");
setara denganstatic_assert(false, "AAA");
di dalam lambda.f(std::integral_constant<int, 1>{});
Wandbox tidak memicu pernyataan: wandbox.org/permlink/UFYAmYwtt1ptsndrJawaban:
Dari [stmt.if] / 2 (penekanan pada saya)
Membaca bahwa orang akan berpikir pernyataan statis akan dihapus, tetapi ini tidak terjadi.
Pernyataan statis dipicu pada fase pertama templat karena kompilator tahu itu selalu salah.
Dari [temp.res] / 8 (penekanan pada saya)
Ya,
False<T>
tergantung pada AndaT
. Masalahnya adalah bahwa lambda generik itu sendiri merupakan templat, danFalse<T>
tidak bergantung pada parameter templat dari lambda.Untuk
T
yangFalse<T>
salah, pernyataan statis akan selalu salah, tidak peduli argumen templat mana yang dikirim ke lambda.Compiler dapat melihat bahwa untuk setiap instantiation dari template
operator()
, pernyataan statis akan selalu memicu untuk T. saat ini.Solusi untuk ini adalah bergantung pada
x
:Contoh langsung
sumber
Aturan biasa di sini adalah [temp.res] / 8 :
Setelah Anda instantiate
foo<T>
, yangstatic_assert
Anda miliki tidak lagi tergantung. Ini menjadistatic_assert(false)
- untuk semua instantiasi yang mungkin dari operator panggilan lambda generikf
. Itu buruk bentuknya, tidak diperlukan diagnostik. Dentang diagnosis, gcc tidak. Keduanya benar.Perhatikan bahwa tidak peduli bahwa
static_assert
di sini adalah dibuang.Ini menjaga
static_assert
ketergantungan dalam lambda generik, dan sekarang kita masuk ke keadaan di mana ada hipotesis yang bisa menjadi spesialisasi yang valid, jadi kita tidak lagi sakit, ndr.sumber