C ++ lambda default argument compiler misbehavior?

Oct 16 2020

Manakah dari C ++ lambda / pernyataan berikut yang seharusnya bekerja sesuai dengan spesifikasi C ++ terbaru?

Konteks jika ini relevan: lihat di sini .

Saya menguji cuplikan kode berikut dengan -std=c++17di Fedora 33 dengan clang 11.0.0 dan gcc 10.2.1.

Pembaruan: Ganti __PRETTY_FUNCTION__dengan __func__untuk kepatuhan standar. Perilaku yang sama dapat diamati.

Update2: Contoh menggunakan const char * s = __func__argumen default untuk memverifikasi bahwa itu harus valid dalam lingkup fungsi (terima kasih kepada @BenVoigt).


1. LLVM __func__dalam argumen default lambda

void clang() {
  [](const char* c = __func__) {std::cout << c << std::endl;}();
}

Perilaku yang diharapkan (CLANG):

  • Cetak clang\n( void clang()untuk __PRETTY_FUNCTION__)

Perilaku yang diamati (CLANG):

  • Peringatan penyusun: warning: predefined identifier is only valid inside function [-Wpredefined-identifier-outside-function]
  • Cetak \n( top level()untuk __PRETTY_FUNCTION__)

2. GCC mengabaikan pernyataan

template <typename L>
constexpr std::string_view methodName(L l) { return l(); }
#define __METHOD_NAME__ (\
  __func__, /* needed for pointer to work */ \
  methodName([](const char* c = __func__) {return std::string_view(c);}) \
)
void gcc1() {
  std::cout << [](const char* c = __func__) { return c; }() << std::endl;  // GCC: This statement doesn't do anything
  std::cout << [](const char* c = __func__) { return c; }("gcc") << std::endl;
  std::cout << __METHOD_NAME__ << std::endl;  // GCC: This statement somehow conflicts with the statements above
}
void gcc2() {
  std::cout << __METHOD_NAME__ << std::endl;  // GCC: This statement itself works
}

Keluaran yang diharapkan (GCC):

gcc1
gcc
gcc1
gcc2

Output yang diamati (GCC):

gcc
gcc2

3. GCC Compile error

void gcc3() {
  std::string_view s = [](const char* c = __func__) { return std::string_view(c); }();
  std::cout << s << std::endl;
}

Perilaku yang diharapkan (GCC): Dikompilasi tanpa masalah.

Perilaku yang diamati (GCC): error: internal compiler error: in finish_expr_stmt

Jawaban

n.'pronouns'm. Oct 16 2020 at 17:01

[class.local] Kelas lokal berada dalam cakupan lingkup yang melingkupi, dan memiliki akses yang sama ke nama di luar fungsi seperti halnya fungsi penutup. [Catatan: Deklarasi di kelas lokal tidak dapat menggunakan (6.2) entitas lokal dari cakupan yang melingkupi. - catatan akhir]

Lambda adalah kelas lokal, dan oleh karena itu ia tidak dapat menggunakan variabel dari lingkup yang melingkupi (misalnya __func__) selain dalam klausa penangkapannya.