Call lambda with another lambda result when its return type is invalid

The following function makes a lambda that calls the second callable with the first callable result. If the first called returns a tuple, it will be applied to the second called.

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)...));
        }
    };
}

However, this does not compile when the returned source returns void, since it will try to call the target with an incomplete type void, so I tried the following:

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, . geuss - decltype, source_return. decltype decltype (source (args...)), , void , void, .

, :

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

callable();

, , , - source_return , void branch. - , args... , ?

EDIT:

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)...);
    };
}
+4
1

, ,

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

target() std::apply std::tuple ( , ) .

0

Source: https://habr.com/ru/post/1695601/


All Articles