多态lambda的默认参数
Default parameters for polymorphic lambda
我试图写一个宏,将缩短lambda表达式语法当单个返回语句是它所需要的。我的第一次尝试是这样的:
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!"));
<<p> 生活例子/strong> Update:正如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!"));
<<p> 生活例子/strong> 更通用,但是从表达式内访问元素的语法不太方便:
#define LR(EXPR) (auto&&... ps)
{ auto p = std::forward_as_tuple(ps...); return EXPR; }
导致
std::cout << []LR(std::get<0>(p))("test");
std::cout << []LR(std::get<0>(p) + std::get<1>(p))(2, 3);
std::cout << []LR(std::get<0>(p) + std::get<1>(p))(std::string("hello "), std::string(" world!"));
<<p> 生活例子/strong> 更新:基于@Oktalist的答案(+1),还可以使用标准提供的占位符:
#include <iostream>
#include <tuple>
#include <functional>
namespace detail
{
template<typename T>
struct tuple_with_placeholder : T
{
using T::T;
template<typename PH>
auto operator[](PH) const
{
return std::get<std::is_placeholder<PH>::value-1>(*this);
}
};
}
#define LR(EXPR) (auto&&... ps) {
detail::tuple_with_placeholder<decltype(std::forward_as_tuple(ps...))> p(ps...);
using namespace std::placeholders;
return EXPR;
}
int main()
{
std::cout << []LR(p[_1])("test");
std::cout << []LR(p[_1]+p[_2])(2, 3);
std::cout << []LR(p[_1]+p[_2])(std::string("hello "), std::string(" world!"));
}
<<p> 生活例子/strong> 基于预处理器的解决方案:
#include <boost/preprocessor/tuple/to_seq.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/cat.hpp>
#include <boost/preprocessor/seq/to_tuple.hpp>
#define _AUTO(_0, _1, name)
(auto&& name)
#define _BODY(...)
{ return __VA_ARGS__; }
#define LR(...)
BOOST_PP_SEQ_TO_TUPLE(BOOST_PP_SEQ_FOR_EACH(_AUTO, _, BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__)))) _BODY
#include <iostream>
int main()
{
std::cout << []LR(x)(x)("test");
std::cout << []LR(x, y)(x + y)(2, 3);
std::cout << []LR(x, y)(x + y)(std::string("hello "), std::string(" world!"));
}
根据您的贡献,我提出了以下实现:
namespace detail
{
struct void_t{};
template<int I> struct int_t{};
template<class TT> void_t get_param(void_t, const TT&)
{
return void_t{};
}
template<int I, class TT> auto get_param(int_t<I>, const TT& p_tuple)
-> std::tuple_element_t<I, TT>&
{
return std::get<I>(p_tuple);
}
}
#define LR(EXPR) (auto&&... ps)
{
auto p = std::forward_as_tuple(ps...);
auto&& p_1 = get_param(std::conditional_t<sizeof...(ps) >= 1,
detail::int_t<0>,
detail::void_t>{}, p);
auto&& p_2 = get_param(std::conditional_t<sizeof...(ps) >= 2,
detail::int_t<1>,
detail::void_t>{}, p);
auto&& p_3 = get_param(std::conditional_t<sizeof...(ps) >= 3,
detail::int_t<2>,
detail::void_t>{}, p);
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);
std::cout << []LR(std::get<3>(p))(1, 2, 3, 4);
}
有人能看出这有什么问题吗?
相关文章:
- 使函数参数默认为周围范围
- 如何将值传递给其参数(默认参数)
- 当“std::make_index_sequence”和“std::index_sequence”用于模板参数默认类型时
- C ,构造器中允许的参考参数默认值
- 哪些规则控制参数默认赋值?
- 错误:上一个规范后给出的参数默认参数
- 是否可以设计一个包含模板参数默认值的类
- 构造函数中参数C++默认值
- 如何设置依赖于其他参数的参数默认值
- C++模板参数默认函数实现
- QInput对话框参数默认值
- g++4.8.2上列表方法参数默认初始化时出错
- 在函数定义中指定参数默认值会导致错误 C2143:语法错误:'='之前缺少')'
- 函数模板:将第一个模板参数默认为第二个
- 模板模板参数默认可以引用其他模板类型的参数
- 参数默认为先例参数的值
- 如何修改一个类,使它只有一个成员函数,所有参数默认
- 内置类型的模板参数默认值
- 是否可以使用构造函数或对象作为其他类方法的参数默认值?
- 模板参数默认为更高版本