Dalam +
ekspresi tersebut +[](){}
adalah +
operator unary . Ini didefinisikan sebagai berikut dalam [expr.unary.op] / 7:
Operand dari +
operator unary harus memiliki aritmatika, enumerasi tanpa batas, atau tipe pointer dan hasilnya adalah nilai argumen.
Lambda bukanlah tipe aritmatika dll., Tetapi dapat dikonversi:
[expr.prim.lambda] / 3
Tipe ekspresi lambda [...] adalah tipe kelas non-union unik dan tidak bernama - disebut tipe closure - yang propertinya dijelaskan di bawah ini.
[expr.prim.lambda] / 6
Jenis penutupan untuk lambda ekspresi tanpa lambda-capture memiliki public
non virtual
non explicit
const
fungsi konversi untuk pointer ke fungsi memiliki parameter dan return yang sama jenis sebagai operator fungsi panggilan jenis penutupan ini. Nilai yang dikembalikan oleh fungsi konversi ini harus menjadi alamat fungsi yang, ketika dipanggil, memiliki efek yang sama seperti memanggil operator panggilan fungsi tipe penutupan.
Oleh karena itu, unary +
memaksa konversi ke tipe penunjuk fungsi, yang untuk lambda ini void (*)()
. Oleh karena itu, tipe ekspresi +[](){}
adalah tipe penunjuk fungsi ini void (*)()
.
Kelebihan muatan kedua void foo(void (*f)())
menjadi Pencocokan Persis dalam peringkat untuk resolusi kelebihan muatan dan oleh karena itu dipilih dengan jelas (karena muatan berlebih pertama BUKAN Pencocokan Persis).
Lambda [](){}
dapat dikonversi ke std::function<void()>
melalui ctor template non-eksplisit std::function
, yang mengambil jenis apa pun yang memenuhi persyaratan Callable
dan CopyConstructible
.
Lambda juga dapat dikonversi void (*)()
melalui fungsi konversi tipe penutupan (lihat di atas).
Keduanya adalah urutan konversi yang ditentukan pengguna, dan memiliki peringkat yang sama. Itulah mengapa resolusi kelebihan beban gagal pada contoh pertama karena ambiguitas.
Menurut Cassio Neri, didukung oleh argumen Daniel Krügler, +
trik unary ini harus ditentukan perilaku, yaitu Anda dapat mengandalkannya (lihat diskusi di komentar).
Namun, saya akan merekomendasikan menggunakan cast eksplisit ke jenis penunjuk fungsi jika Anda ingin menghindari ambiguitas: Anda tidak perlu bertanya pada SO apa itu dan mengapa berfungsi;)
std::bind
kestd::function
objek yang bisa disebut mirip dengan nilai fungsi.operator +()
tipe penutupan tanpa kewarganegaraan. Asumsikan bahwa operator ini mengembalikan sesuatu selain penunjuk ke fungsi yang dikonversi menjadi tipe penutupan. Kemudian, ini akan mengubah perilaku program yang dapat diamati yang melanggar 5.1.2 / 3. Tolong beri tahu saya jika Anda setuju dengan alasan ini.operator +
, tetapi ini membandingkan dengan situasi yangoperator +
awalnya tidak ada . Namun tidak ditentukan bahwa tipe penutupan tidak bolehoperator +
kelebihan beban. "Implementasi dapat mendefinisikan jenis penutupan secara berbeda dari apa yang dijelaskan di bawah asalkan ini tidak mengubah perilaku program yang dapat diamati selain oleh [...]" tetapi IMO menambahkan operator tidak mengubah jenis penutupan menjadi sesuatu yang berbeda dari apa adalah "dijelaskan di bawah".operator +()
sama persis dengan yang dijelaskan oleh standar. Standar memungkinkan implementasi untuk melakukan sesuatu yang berbeda dari apa yang ditentukan. Misalnya, menambahkanoperator +()
. Namun, jika perbedaan ini dapat diamati oleh suatu program, maka itu ilegal. Suatu kali saya bertanya di comp.lang.c ++. Dimoderasi apakah tipe closure bisa menambahkan typedef untukresult_type
dan yang laintypedefs
diperlukan untuk membuatnya bisa beradaptasi (misalnya olehstd::not1
). Saya diberitahu bahwa itu tidak bisa karena ini dapat diamati. Saya akan mencoba mencari tautannya.