首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当返回类型为void时,调用lambda和其他lambda结果

当返回类型为void时,调用lambda和其他lambda结果
EN

Stack Overflow用户
提问于 2018-03-31 19:26:21
回答 1查看 184关注 0票数 4

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

代码语言:javascript
复制
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)...));
        }
    };
}

但是,当源callable返回void时,这不会编译,因为它将尝试调用具有不完整类型void的target,所以我尝试了以下方法:

代码语言:javascript
复制
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。我猜在推断source_return的时候,decltype有问题。我试图将source的结果赋给一个变量,以便解密该变量,而不是decltype(source(args...))但它给我的错误是,变量是不完整的void类型,在它实际上返回void的情况下,所以我必须在实际调用source之前检查它。

下面是一个无法编译的管道使用示例:

代码语言:javascript
复制
auto callable = pipeline([]{ return 10 },
                         [](size_t val){ return val * 10});

callable();

它不能编译的原因是,由于某种原因,它使用的source_return与空分支相同。任何人都知道当我用args调用时,我如何计算出源的返回类型……以一种更健壮的方式?

编辑:

我通过使用call_pipeline帮助器函数让它工作。我仍然不明白为什么这个可以工作,而另一个不行。

代码语言:javascript
复制
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)...);
    };
}
EN

回答 1

Stack Overflow用户

发布于 2018-03-31 21:19:57

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

代码语言:javascript
复制
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()

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49587203

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档