【发布时间】:2018-02-26 06:04:22
【问题描述】:
上下文
首先,一些上下文:我使用一个名为nothing 的空struct 来模拟类似于"regular void" 的东西,以便美化一些依赖于将多个函数对象链接在一起的接口。
struct nothing { };
示例用法:
when_all([]{ return 0; }, []{ }, []{ return 'a'; })
.then([](int, char){ }); // result of lambda in the middle ignored
在上面的示例中,实际发生的情况是我将传递给when_all 的函数对象的所有结果打包在std::tuple 中,将void 转换为nothing (在此示例中:std::tuple<int, nothing, char>),然后我使用一个名为 apply_ignoring_nothing 的辅助函数,它通过解包 std::tuple 来调用函数对象,忽略 nothing 的元素。
auto f_then = [](int, char){ };
auto args = std::tuple{0, nothing{}, 'a'};
apply_ignoring_nothing(f_then, args); // compiles
apply_ignoring_nothing 是根据call_ignoring_nothing 实现的。
问题
我有一个函数call_ignoring_nothing,签名如下:
template <typename F, typename... Ts>
constexpr decltype(auto) call_ignoring_nothing(F&& f, Ts&&... xs);
此函数将通过完美转发编译时is_nothing_v<T>返回false的所有xs...来调用f。
is_nothing_v定义如下:
template <typename T>
inline constexpr bool is_nothing_v = std::is_same_v<std::decay_t<T>, nothing>;
我实现call_ignoring_nothing 的方式是递归。基本情况只需要 f 并简单地调用它:
#define FWD(x) ::std::forward<decltype(x)>(x)
template <typename F>
constexpr decltype(auto) call_ignoring_nothing(F&& f)
{
return returning_nothing_instead_of_void(FWD(f));
}
递归案例采用f、x 和xs...,如果!is_nothing_v<decltype(f)> 通过 lambda 有条件地绑定x 作为f 的参数之一。然后它在 call_ignoring_nothing 上递归,将新创建的 lambda 传递为 f:
template <typename F, typename T, typename... Ts>
constexpr decltype(auto) call_ignoring_nothing(F&& f, T&& x, Ts&&... xs)
{
return call_ignoring_nothing(
[&](auto&&... ys) -> decltype(auto) {
if constexpr(is_nothing_v<T>)
{
return FWD(f)(FWD(ys)...);
}
else
{
return FWD(f)(FWD(x), FWD(ys)...);
}
},
FWD(xs)...);
}
我想以迭代方式实现call_ignoring_nothing,可能利用pack 扩展 来过滤掉参数而不递归。
是否可以在不递归的情况下实现call_ignoring_nothing?我想不出任何允许在包扩展期间过滤掉参数的技术。
【问题讨论】:
-
重申我在 Slack 上提出的建议:将包变成一个元组。为元组生成索引序列。过滤索引序列(甚至可能使用类型级别的过滤器,将序列转换为
integral_constant<std::size_t, Is>...)。模式匹配。展开get<FilteredIs>(tuple)...。 -
还从 Slack 移植了我的评论,作为对“这不是将问题转移到
filter内的 concat 级别”的答案 - 您可以优化join以避免总是递归;可以在metal 中找到一个示例。 -
正如 Desproges 所说:“就我自己的观点而言,我经常提到的观点......”我认为任何人都可以在这里发布答案。
标签: c++ templates metaprogramming template-meta-programming c++17