Saya memiliki persepsi bahwa, jenis lambda adalah penunjuk fungsi. Ketika saya melakukan tes berikut, saya menemukan itu salah ( demo ).
#define LAMBDA [] (int i) -> long { return 0; }
int main ()
{
long (*pFptr)(int) = LAMBDA; // ok
auto pAuto = LAMBDA; // ok
assert(typeid(pFptr) == typeid(pAuto)); // assertion fails !
}
Apakah kode di atas kehilangan poin? Jika tidak, apa typeof
ekspresi lambda ketika disimpulkan dengan auto
kata kunci?
Jawaban:
Jenis ekspresi lambda tidak ditentukan.
Tetapi mereka umumnya hanyalah gula sintaksis untuk para fungsional. Lambda diterjemahkan langsung ke dalam sebuah functor. Semua yang ada di dalam
[]
akan diubah menjadi parameter konstruktor dan anggota objek functor, dan parameter di dalamnya()
diubah menjadi parameter untuk functoroperator()
.Sebuah lambda yang tidak menangkap variabel (tidak ada di dalam
[]
) dapat diubah menjadi penunjuk fungsi (MSVC2010 tidak mendukung ini, jika itu kompiler Anda, tetapi konversi ini adalah bagian dari standar).Tapi tipe lambda yang sebenarnya bukanlah penunjuk fungsi. Ini beberapa jenis functor yang tidak ditentukan.
sumber
operator()
pada dasarnya stackoverflow.com/questions/356950/c-functors-and-their-usesIni adalah struktur unik tanpa nama yang membebani operator pemanggil fungsi. Setiap contoh lambda memperkenalkan tipe baru.
Dalam kasus khusus lambda yang tidak menangkap, struktur tersebut memiliki konversi implisit ke penunjuk fungsi.
sumber
type_info::name()
adalah implementasi-didefinisikan, sehingga dapat mengembalikan apapun. Dalam praktiknya, kompilator akan menamai tipe tersebut demi linker.Klausul tersebut melanjutkan ke daftar berbagai properti dari jenis ini. Berikut beberapa sorotan:
Konsekuensi dari bagian terakhir ini adalah, jika Anda menggunakan sebuah konversi, Anda akan dapat menetapkannya
LAMBDA
kepFptr
.sumber
#include <iostream> #include <typeinfo> #define LAMBDA [] (int i)->long { return 0l; } int main () { long (*pFptr)(int) = LAMBDA; // ok auto pAuto = LAMBDA; // ok std::cout<<typeid( *pAuto ).name() << std::endl; std::cout<<typeid( *pFptr ).name() << std::endl; std::cout<<typeid( pAuto ).name() << std::endl; std::cout<<typeid( pFptr ).name() << std::endl; }
Jenis fungsi memang sama, tetapi lambda memperkenalkan jenis baru (seperti functor).
sumber
__PRETTY_FUNCTION__
, sepertitemplate<class T> const char* pretty(T && t) { return __PRETTY_FUNCTION__; }
, dan menanggalkan ekstra jika mulai ramai. Saya lebih suka melihat langkah-langkah yang ditunjukkan dalam penggantian template. Jika Anda tidak ada__PRETTY_FUNCTION__
, ada alternatif untuk MSVC, dll., Tetapi hasilnya selalu bergantung pada kompilator karena alasan yang sama CXXABI diperlukan.Perlu juga dicatat bahwa lambda dapat diubah menjadi penunjuk fungsi. Namun typeid <> mengembalikan objek non-trvial yang harus berbeda dari lambda ke penunjuk fungsi generik. Jadi pengujian untuk typeid <> bukanlah asumsi yang valid. Secara umum C ++ 11 tidak ingin kita khawatir tentang spesifikasi tipe, semua itu penting jika tipe tertentu dapat dikonversi ke tipe target.
sumber
Solusi praktis dari Bagaimana cara menyimpan objek boost :: bind sebagai anggota kelas? , coba
boost::function<void(int)>
ataustd::function<void(int)>
.sumber