I'm trying to write a macro that would shorten lambda expression syntax when single return statement is all it's needed. My first attempt looked like this:
struct void_t{};
#define LR(EXPR) (auto&& p_1 = void_t{}, auto&& p_2 = void_t{}, auto&& p_3 = void_t{}){ return EXPR; }
Unfortunately it does not work as I would expect. Default arguments are basically ignored and I cannot call this lambda with less than three params:
std::cout << []LR(p_1)("test"); // compile error
std::cout << []LR(p_1 + p_2)(2, 3); // compile error
std::cout << []LR(p_1 + p_2)(std::string("hello "), std::string(" world!")); // compile error
std::cout << []LR(p_1 + p_2)(2, 3, 0); // OK
I managed to devise some convoluted workaround that seemed to work but it has issues:
template<class LT> struct lambda_wrapper
{
lambda_wrapper(LT p_lambda): m_lambda(p_lambda){}
template<class T1, class T2, class T3>
auto operator()(T1&& p_1, T2&& p_2, T3&& p_3) const
{
return m_lambda(std::forward<T1>(p_1),
std::forward<T2>(p_2),
std::forward<T3>(p_3));
}
template<class T1, class T2> auto operator()(T1&& p_1, T2&& p_2) const
{
return m_lambda(std::forward<T1>(p_1), std::forward<T2>(p_2), void_t{});
}
template<class T1> auto operator()(T1&& p_1) const
{
return m_lambda(std::forward<T1>(p_1), void_t{}, void_t{});
}
auto operator()() const
{
return m_lambda(void_t{}, void_t{}, void_t{});
}
private:
LT m_lambda;
};
template <class LT> lambda_wrapper<LT> operator++(LT&& p_lambda, int)
{
return {std::forward<LT>(p_lambda)};
}
#define LR(EXPR) (auto&& p_1, auto&& p_2, auto&& p_3){ return EXPR; }++
Anybody has a better idea?
UPDATE:
Expanding upon your contributions I came up with following implementation:
struct void_t{};
template<class TT> constexpr void_t& get_param(void_t, const TT&, void_t& p_void)
{
return p_void;
}
template<size_t I, class TT>
constexpr auto get_param(std::integral_constant<size_t, I>, const TT& p_tuple, void_t& p_void)
-> std::tuple_element_t<I, TT>&
{
return std::get<I>(p_tuple);
}
#define LR(EXPR) (auto&&... ps) \
{\
auto l_tuple_sflj123 = std::forward_as_tuple(ps...);\
typedef typename std::conditional<sizeof...(ps) >= 1, std::integral_constant<size_t, 0>, void_t>::type type_1;\
typedef typename std::conditional<sizeof...(ps) >= 2, std::integral_constant<size_t, 1>, void_t>::type type_2;\
typedef typename std::conditional<sizeof...(ps) >= 3, std::integral_constant<size_t, 2>, void_t>::type type_3;\
void_t l_void_pfjaos43{};\
auto&& p_1 = get_param(type_1{}, l_tuple_sflj123, l_void_pfjaos43);\
auto&& p_2 = get_param(type_2{}, l_tuple_sflj123, l_void_pfjaos43);\
auto&& p_3 = get_param(type_3{}, l_tuple_sflj123, l_void_pfjaos43);\
return EXPR;\
}
int main() {
std::cout << []LR(p_1)("test ", "test2");
std::cout << []LR(p_1 + p_2)(std::string("Hallo "), std::string("World! "));
int l_1 = 4;
std::cout << [=]LR(p_1 + p_2 + p_3 + l_1)(1, 2, 3);
}
Can you see any problems with this?
Aucun commentaire:
Enregistrer un commentaire