gpt4 book ai didi

c++ - 多态 lambda 的默认参数

转载 作者:太空狗 更新时间:2023-10-29 19:57:44 24 4
gpt4 key购买 nike

我正在尝试编写一个宏来缩短 lambda 表达式语法,当它只需要一个 return 语句时。我的第一次尝试是这样的:

struct void_t{};                                                                                                                                     

#define LR(EXPR) (auto&& p_1 = void_t{}, auto&& p_2 = void_t{}, auto&& p_3 = void_t{}){ return EXPR; }

不幸的是,它没有像我预期的那样工作。默认参数基本上被忽略,我不能用少于三个参数调用这个 lambda:

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

我设法设计了一些看似可行但存在问题的复杂解决方法:

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; }++

有人有更好的主意吗?

最佳答案

根据 Daniel 的回答,我们可以将元组索引编码为 std::integral_constant 类型,并使用 operator[ 编写 std::tuple 的扩展[ ] 可以从其参数类型推导出索引的模板:

namespace detail {
template <typename... Ts> struct tuple : std::tuple<Ts...> {
using std::tuple<Ts...>::tuple;
template <typename T> constexpr auto operator[](T)
-> std::tuple_element_t<T::value, std::tuple<Ts...>>
{ return std::get<T::value>(*this); }
};
template <typename... Ts> constexpr tuple<Ts&&...> forward_as_tuple(Ts&&... vs) {
return tuple<Ts&&...>{ std::forward<Ts>(vs)... };
}
namespace placeholders {
constexpr std::integral_constant<size_t, 0> _0;
constexpr std::integral_constant<size_t, 1> _1;
constexpr std::integral_constant<size_t, 2> _2;
//...
}
}

#define LR(EXPR) (auto&&... _ps) \
{ using namespace detail::placeholders; auto p = detail::forward_as_tuple(_ps...); return EXPR; }

导致

std::cout << []LR(p[_0])("test");
std::cout << []LR(p[_0] + p[_1])(2, 3);
std::cout << []LR(p[_0] + p[_1])(std::string("hello "), std::string(" world!"));

Live example

更新:正如 Daniel 在评论中提到的,我们可以为每个参数数量专门化我们的元组类型,并为元组元素命名别名:

namespace detail {
template <typename... Ts> struct tuple : std::tuple<Ts...> {
using std::tuple<Ts...>::tuple;
};
template <typename T0> struct tuple<T0> : std::tuple<T0> {
using std::tuple<T0>::tuple;
T0&& _0 = std::get<0>(*this);
};
template <typename T0, typename T1> struct tuple<T0, T1> : std::tuple<T0, T1> {
using std::tuple<T0, T1>::tuple;
T0&& _0 = std::get<0>(*this);
T1&& _1 = std::get<1>(*this);
};
template <typename T0, typename T1, typename T2> struct tuple<T0, T1, T2> : std::tuple<T0, T1, T2> {
using std::tuple<T0, T1, T2>::tuple;
T0&& _0 = std::get<0>(*this);
T1&& _1 = std::get<1>(*this);
T2&& _2 = std::get<2>(*this);
};
//...
template <typename... Ts> constexpr tuple<Ts&&...> forward_as_tuple(Ts&&... vs) {
return tuple<Ts&&...>{ std::forward<Ts>(vs)... };
}
}

#define LR(EXPR) (auto&&... _ps) \
{ auto p = detail::forward_as_tuple(_ps...); return EXPR; }

因此:

std::cout << []LR(p._0)("test");
std::cout << []LR(p._0 + p._1)(2, 3);
std::cout << []LR(p._0 + p._1)(std::string("hello "), std::string(" world!"));

Live example

关于c++ - 多态 lambda 的默认参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30397630/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com