gpt4 book ai didi

c++ - 当其返回类型为 void 时,使用其他 lambda 结果调用 lambda

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:21:00 24 4
gpt4 key购买 nike

以下函数生成一个 lambda,它使用第一个可调用对象的结果调用第二个可调用对象。如果第一个可调用对象返回一个元组,它将应用于第二个可调用对象。

template<typename T>
struct is_tuple : std::false_type{};

template<typename... T>
struct is_tuple<std::tuple<T...>> : std::true_type{};

template<typename S, typename T>
constexpr decltype(auto) pipeline(S&& source, T&& target)
{
return [callables = std::tuple<S, T>(std::forward<S>(source), std::forward<T>(target))]
(auto&&... args)
{
const auto&[source, target] = callables;

using source_return = decltype(source(args...));

if constexpr(is_tuple<source_return>::value)
{
return std::apply(target, source(std::forward<decltype(args)>(args)...));
}
else
{
return target(source(std::forward<decltype(args)>(args)...));
}
};
}

然而,当源可调用返回 void 时,这不会编译,因为它会尝试调用不完整类型 void 的目标,所以我尝试了以下操作:

template<typename S, typename T>
constexpr decltype(auto) pipeline(S&& source, T&& target)
{
return [callables = std::tuple<S, T>(std::forward<S>(source), std::forward<T>(target))]
(auto&&... args)
{
const auto&[source, target] = callables;

using source_return = decltype(source(args...));

if constexpr(is_tuple<source_return>::value)
{
return std::apply(target, source(std::forward<decltype(args)>(args)...));
}
else if constexpr(std::is_void_v<source_return>)
{
source(std::forward<decltype(args)>(args)...);
return target();
}
else
{
return target(source(std::forward<decltype(args)>(args)...));
}
};
}

但这似乎不知何故不起作用,因为它总是采用与 void 分支相同的方法,即使源函数在任何情况下都不能返回 void。我猜 decltype 推导 source_return 有问题。我试图将 source 的结果分配给一个变量来 decltype 该变量而不是 decltype(source(args...)) 但是它给了我一个错误,即在它实际返回的情况下变量是不完整类型 void无效,所以我必须在实际调用源之前检查它。

这是一个未编译的管道用法示例:

auto callable = pipeline([]{ return 10 },
[](size_t val){ return val * 10});

callable();

它不编译的原因是因为出于某种原因它需要 source_return 与 void 分支相同。任何人都知道我如何在使用 args 调用时找出 source 的返回类型...以更稳健的方式?

编辑:

我通过使用 call_pipeline 辅助函数让它工作。我仍然不明白为什么这个会起作用而另一个却不起作用。

template<typename S, typename T, typename... Args>
constexpr decltype(auto) call_pipeline(const S& source, const T& target, Args&&... args)
{
using source_return = decltype(source(std::forward<Args>(args)...));

if constexpr(std::is_void_v<source_return>)
{
source(std::forward<Args>(args)...);
return target();
}
else
{
if constexpr(is_tuple<source_return>::value)
{
return std::apply(target, source(std::forward<Args>(args)...));
}
else
{
return target(source(std::forward<Args>(args)...));
}
}
}

template<typename S, typename T>
constexpr decltype(auto) pipeline(S&& source_init, T&& target_init)
{
return [callables = std::tuple<S, T>(std::forward<S>(source_init),
std::forward<T>(target_init))]
(auto&&... args)
{
const auto&[source, target] = callables;
return call_pipeline(source, target, std::forward<decltype(args)>(args)...);
};
}

最佳答案

不确定是否按您的方式行事,但我提出以下替代方案

template<typename S, typename T>
constexpr decltype(auto) pipeline(S&& source, T&& target)
{
return [callables = std::tuple<S, T>(std::forward<S>(source),
std::forward<T>(target))]
(auto&&... args)
{
const auto&[source, target] = callables;

auto tplr = [](auto s, auto && ... as)
{
using source_return
= decltype(s(std::forward<decltype(as)>(as)...));
if constexpr ( is_tuple<source_return>::value )
return s(std::forward<decltype(as)>(as)...);
else if constexpr ( std::is_void_v<source_return> )
{
s(std::forward<decltype(as)>(as)...);
return std::make_tuple();
}
else
return std::make_tuple(s(std::forward<decltype(as)>(as)...));
}(source, std::forward<decltype(args)>(args)...);

std::apply(target, tplr);
};
}

这个想法是通过 std::apply 使用 std::tuple (可能为空)参数调用 target() .

关于c++ - 当其返回类型为 void 时,使用其他 lambda 结果调用 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49587203/

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