Katakanlah kita memiliki makro seperti ini
#define FOO(type,name) type name
Yang bisa kita gunakan seperti
FOO(int, int_var);
Tetapi tidak selalu sesederhana itu:
FOO(std::map<int, int>, map_var); // error: macro "FOO" passed 3 arguments, but takes just 2
Tentu saja kami bisa melakukan:
typedef std::map<int, int> map_int_int_t;
FOO(map_int_int_t, map_var); // OK
yang tidak terlalu ergonomis. Ketidaksesuaian tipe Plus harus ditangani. Ada ide bagaimana mengatasi ini dengan makro?
c++
c
macros
c-preprocessor
PoP
sumber
sumber
Jawaban:
Karena kurung sudut juga dapat mewakili (atau terjadi pada) operator perbandingan
<
,>
,<=
dan>=
, ekspansi makro tidak bisa mengabaikan koma di dalam tanda kurung sudut seperti itu tidak dalam tanda kurung. (Ini juga masalah untuk tanda kurung siku dan tanda kurung siku, meskipun itu biasanya terjadi sebagai pasangan seimbang.) Anda bisa mengapit argumen makro dalam tanda kurung:Masalahnya adalah bahwa parameter tetap dalam tanda kurung di dalam perluasan makro, yang mencegahnya dibaca sebagai tipe di sebagian besar konteks.
Trik yang bagus untuk mengatasinya adalah bahwa di C ++, Anda dapat mengekstrak nama jenis dari nama jenis dalam tanda kurung menggunakan jenis fungsi:
Karena tipe fungsi pembentuk mengabaikan tanda kurung ekstra, Anda bisa menggunakan makro ini dengan atau tanpa tanda kurung di mana nama tipe tidak menyertakan koma:
Di C, tentu saja, ini tidak diperlukan karena nama tipe tidak boleh berisi koma di luar tanda kurung. Jadi, untuk makro lintas bahasa Anda bisa menulis:
sumber
template<class KeyType, class ValueType> void SomeFunc(FOO(std::map<KeyType, ValueType>) element) {}
Jika saya menerapkan solusi ini di sini, struct di belakang makro menjadi tipe dependen, dan awalan nama tipe sekarang diperlukan pada tipe. Anda dapat menambahkannya, tetapi pengurangan jenis telah rusak, jadi Anda sekarang harus membuat daftar argumen jenis secara manual untuk memanggil fungsi tersebut. Saya akhirnya menggunakan metode temple untuk mendefinisikan makro untuk koma. Ini mungkin tidak terlihat cantik, tetapi berfungsi dengan sempurna.[]
dan{}
, mereka tidak, hanya bekerja dengan()
sedih. Lihat: Namun, tidak ada persyaratan untuk tanda kurung siku atau kawat gigi untuk menyeimbangkan ...#define PROTECT(...) argument_type<void(__VA_ARGS__)>::type
. Meneruskan argumen sekarang dengan mudah dapat dilakukan bahkan melalui beberapa makro dan untuk tipe sederhana Anda dapat mengabaikan PROTECT. Namun jenis fungsi menjadi penunjuk fungsi ketika dievaluasi seperti iniJika Anda tidak dapat menggunakan tanda kurung dan tidak menyukai solusi SINGLE_ARG Mike, cukup tentukan COMMA:
Ini juga membantu jika Anda ingin merangkai beberapa argumen makro, seperti dalam
yang mencetak
std::map<int , int> has typeid name "St3mapIiiSt4lessIiESaISt4pairIKiiEEE"
.sumber
#define STRVX(...) STRV(__VA_ARGS__)
dan#define STRV(...) # __VA_ARGS__
, makastd::cout << STRV(type<A COMMA B>) << std::endl;
akan mencetaktype<A COMMA B>
danstd::cout << STRVX(type<A COMMA B>) << std::endl;
akan mencetaktype<A , B>
. (STRV
untuk "variadic stringify", danSTRVX
untuk "extended variadic stringify".)COMMA
makro sejak awal. Itulah yang akhirnya saya dapatkan.Jika preprocessor Anda mendukung makro variadic:
Jika tidak, ini sedikit lebih membosankan:
sumber
Definisikan
FOO
sebagaiKemudian panggil selalu dengan tanda kurung di sekitar argumen tipe, misalnya
Tentu saja merupakan ide yang bagus untuk memberikan contoh pemanggilan dalam komentar tentang definisi makro.
sumber
UNPACK
dilakukan jika digunakan seperti ini) UNPACK type name
? Mengapatype
mendapatkan tipe dengan benar saat digunakan) UNPACK type name
? Sebenarnya apa yang terjadi disini?Setidaknya ada dua cara untuk melakukan ini. Pertama, Anda bisa menentukan makro yang membutuhkan banyak argumen:
jika Anda melakukannya, Anda mungkin mendapati bahwa Anda akhirnya menentukan lebih banyak makro untuk menangani lebih banyak argumen.
Kedua, Anda dapat meletakkan tanda kurung di sekitar argumen:
jika Anda melakukannya, Anda mungkin menemukan bahwa tanda kurung tambahan mengacaukan sintaks hasil.
sumber
Ini dimungkinkan dengan P99 :
Kode di atas secara efektif hanya menghapus koma terakhir dalam daftar argumen. Periksa dengan
clang -E
(P99 membutuhkan kompiler C99).sumber
Jawaban sederhananya adalah Anda tidak bisa. Ini adalah efek samping dari pilihan
<...>
argumen template; yang<
dan>
juga muncul dalam konteks yang tidak seimbang sehingga mekanisme makro tidak dapat diperpanjang untuk menangani mereka seperti itu menangani tanda kurung. (Beberapa anggota komite telah memperdebatkan token yang berbeda, katakanlah(^...^)
, tetapi mereka tidak dapat meyakinkan sebagian besar masalah menggunakan<...>
.)sumber
(^...^)
ini adalah satu wajah bahagia :)