Apakah lambda yang dapat ditangkap dijamin kosong oleh standar?

12

Saya sedang mencari cara untuk mengidentifikasi lambda kosong (tidak bisa ditangkap) dari lambda lain dalam fungsi templat. Saat ini saya menggunakan C ++ 17 tapi saya juga penasaran untuk C ++ 20 jawaban juga.

Kode saya terlihat seperti ini:

template<typename T>
auto func(T lambda) {
    // The aguments of the lambdas are unknown

    if constexpr (/* is captureless */) {
        // do stuff
    }
}

Apakah dijamin oleh standar C ++ (17 atau 20) bahwa lambda yang tidak dapat ditangkap, yang dapat dikonversi ke pointer fungsi, juga akan membuat std::is_emptyhasil menjadi benar?

Ambil kode ini sebagai contoh:

auto a = []{}; // captureless
auto b = [c = 'z']{}; // has captures

static_assert(sizeof(a) == sizeof(b)); // Both are the same size
static_assert(!std::is_empty_v<decltype(b)>); // It has a `c` member
static_assert(std::is_empty_v<decltype(a)>); // Passes. It is guaranteed?

Contoh langsung

Guillaume Racicot
sumber
2
Jika Anda hanya peduli dengan lambdas non-templat, Anda dapat menggunakan SFINAE untuk memeriksa apakah konversi ke penunjuk fungsi ( +lambda) terbentuk dengan baik.
HolyBlackCat
@HolyBlackCat Saya memikirkan hal itu, tetapi sejauh yang saya ingat, MSVC tidak mengizinkannya karena mereka membebani operator konversi.
Guillaume Racicot
@GuillaumeRacicot MS memaparkan operator konversi terpisah untuk semua konvensi panggilan yang tersedia. Cukup pilih satu dan coba konversikan lambda ke fungsi pointer yang sebanding, dan periksa apakah itu berhasil atau gagal.
Remy Lebeau
+tampaknya bekerja di sini .
HolyBlackCat

Jawaban:

13

Tidak, pada kenyataannya, standar secara eksplisit memberikan izin untuk lambdas untuk memiliki ukuran yang tidak sesuai dengan deklarasi mereka. [expr.prim.lambda.closure] / 2 menyatakan

Jenis penutupan dideklarasikan dalam ruang lingkup blok terkecil, ruang kelas, atau ruang lingkup namespace yang berisi ekspresi lambda yang sesuai. [Catatan: Ini menentukan set ruang nama dan kelas yang terkait dengan tipe penutupan ([basic.lookup.argdep]). Tipe parameter dari lambda-declarator tidak memengaruhi ruang nama dan kelas yang terkait ini. - catatan akhir] Jenis penutupan bukan tipe agregat. Suatu implementasi dapat mendefinisikan jenis penutupan berbeda dari apa yang dijelaskan di bawah asalkan ini tidak mengubah perilaku yang dapat diamati dari program selain dengan mengubah:

  • ukuran dan / atau perataan jenis penutupan,

  • apakah tipe penutupan dapat disalin secara sepele ([class.prop]), atau (2.3)

  • apakah tipe penutupan adalah kelas tata letak standar ([class.prop]).

Suatu implementasi tidak akan menambahkan anggota tipe referensi nilai ke tipe penutupan.

penekanan milikku

Jadi ini memungkinkan implementasi untuk memberikan lambda anggota bahkan jika itu kurang penangkapan. Saya tidak berpikir implementasi apa pun akan pernah, tetapi mereka diizinkan secara hukum untuk melakukannya.

NathanOliver
sumber