ジェネリックラムダをもっと手軽に書くためのマクロ
ラムダのキャプチャは無くてはならないものだけれど,たいていの場合は [&]
とかで済んでしまう.また,引数の型もジェネリックラムダの登場で,だいたい auto
で済んでしまうようになったので,こんな感じで書けると良いなぁと思うようになった.
std::vector<int> v = {1,2,3,4,5}; auto product = boost::accumulate(v, 1, lambda(acc, i){ return acc * i; });
つまり,lambda(x, y, ...)
が [&](auto const& x, auto const& y, ...)
に展開されるようなマクロをつくると便利かなーと思った.
なので,こんなマクロあれば良いなーとどことなくそれっぽい方角へつぶやいたところ,
— でちまるさん(実際かわいい) (@decimalbloat) January 28, 2014
と言われてしまったので泣きながら Boost.PP のドキュメントを読んでいたら @fimbul11 (id:fimbul) さんがささっと実装してくれた.このままツイートが流れてしまうのも勿体ないと思ったのでメモしておく.
#define BOOST_PP_VARIADICS #include <boost/preprocessor.hpp> #define lambda_impl(r, data, i, elem) auto const& elem\ BOOST_PP_COMMA_IF(BOOST_PP_NOT_EQUAL(data, i)) #define lambda(...) [&](\ BOOST_PP_SEQ_FOR_EACH_I(lambda_impl,\ BOOST_PP_DEC(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)),\ BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)))
さすがにマクロ名 lambda
はやりすぎかもしれないので適切に変更して活用したい.fimbul さんありがとうございました.
追記(1/30)
せっかくなので Boost 無しでつくってみた.引数は 16 まで対応で,上記のコードでは対応できていない,引数が0個の場合にも対応させた.IS_EMPTY()
マクロはやり方を思いつかなかったのでネットから拾ってきた.
// IS_EMPTY() from http://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ #define HAS_COMMA_I(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, ...) a15 #define HAS_COMMA(...) HAS_COMMA_I(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) #define TRIGGER_PARENTHESIS(...) , #define IS_EMPTY(...) \ IS_EMPTY_I(HAS_COMMA(__VA_ARGS__), \ HAS_COMMA(TRIGGER_PARENTHESIS __VA_ARGS__), \ HAS_COMMA(__VA_ARGS__ (/*empty*/)), \ HAS_COMMA(TRIGGER_PARENTHESIS __VA_ARGS__ (/*empty*/))) #define CAT5(a0, a1, a2, a3, a4) a0 ## a1 ## a2 ## a3 ## a4 #define IS_EMPTY_I(a0, a1, a2, a3) HAS_COMMA(CAT5(IS_EMPTY_CASE_, a0, a1, a2, a3)) #define IS_EMPTY_CASE_0001 , #define VARIADIC_SIZE(...) VARIADIC_SIZE_I(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,) #define VARIADIC_SIZE_I(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, size, ...) size #define LAMBDA_16(a, ...) auto const& a, LAMBDA_15(__VA_ARGS__) #define LAMBDA_15(a, ...) auto const& a, LAMBDA_14(__VA_ARGS__) #define LAMBDA_14(a, ...) auto const& a, LAMBDA_13(__VA_ARGS__) #define LAMBDA_13(a, ...) auto const& a, LAMBDA_12(__VA_ARGS__) #define LAMBDA_12(a, ...) auto const& a, LAMBDA_11(__VA_ARGS__) #define LAMBDA_11(a, ...) auto const& a, LAMBDA_10(__VA_ARGS__) #define LAMBDA_10(a, ...) auto const& a, LAMBDA_9(__VA_ARGS__) #define LAMBDA_9(a, ...) auto const& a, LAMBDA_8(__VA_ARGS__) #define LAMBDA_8(a, ...) auto const& a, LAMBDA_7(__VA_ARGS__) #define LAMBDA_7(a, ...) auto const& a, LAMBDA_6(__VA_ARGS__) #define LAMBDA_6(a, ...) auto const& a, LAMBDA_5(__VA_ARGS__) #define LAMBDA_5(a, ...) auto const& a, LAMBDA_4(__VA_ARGS__) #define LAMBDA_4(a, ...) auto const& a, LAMBDA_3(__VA_ARGS__) #define LAMBDA_3(a, ...) auto const& a, LAMBDA_2(__VA_ARGS__) #define LAMBDA_2(a, ...) auto const& a, LAMBDA_1(__VA_ARGS__) #define LAMBDA_1(a) auto const& a #define lambda(...) LAMBDA_III(IS_EMPTY(__VA_ARGS__))(__VA_ARGS__) #define LAMBDA_III(b) LAMBDA_IIII(b) #define LAMBDA_IIII(b) LAMBDA_ARGS_##b #define LAMBDA_ARGS_1 LAMBDA_0 #define LAMBDA_ARGS_0(...) LAMBDA_0(LAMBDA_I(VARIADIC_SIZE(__VA_ARGS__))(__VA_ARGS__)) #define LAMBDA_I(n) LAMBDA_II(n) #define LAMBDA_II(size) LAMBDA_##size #define LAMBDA_0 [&]