我可以获取多个链接函数调用的返回类型吗? [英] Can I get the return type of multiple chained functions calls?

查看:90
本文介绍了我可以获取多个链接函数调用的返回类型吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将函数存储在有序集合中,然后将所有函数应用于某个集合,这将导致获得经过大量修改的值,并将其存储在另一个集合中.我的最初尝试包括创建一个所述函数的std::tuple并尝试获取将所有这些函数应用于特定类型的结果类型(std::invoke_result):

I would like to store functions in an ordered collection and then apply all of them to a certain collection, which would result in obtaining heavily modified values, stored in another collection. My initial attempt consisted of creating an std::tuple of said functions and trying to get the result type (std::invoke_result) of applying all of them to a certain type:

int main() {
    auto multiply   = [](const auto arg){ return arg * arg; };
    auto change     = [](const auto arg){ return std::vector{arg}; };
    auto to_string  = [](const auto arg){ return arg.size() + " size"; };

    auto functions = std::make_tuple(multiply, change, to_string);

    std::vector<int> source{1, 2, 3, 4};

    using f_type = decltype(functions);
    using last_type =
            std::tuple_element_t<std::tuple_size_v<f_type> - 1, f_type>;
    using result_type =
            std::invoke_result_t<last_type, /* size - 2 ret type and so on */>;

    /* 
     * result_type is the type of applying *multiply* to int (type of *source*),
     * then applying *change* to the result of *multiply* and then applying
     * *to_string* to the result of *change*. Should be std::string.
     */
    std::vector<result_type> results{};
}

问题在于std::invoke_result_t的第二个template参数需要一种类型,该参数将传递给last_type类型的对象的调用运算符.这就需要在最后一个元素的返回类型之前减去一个,以此类推(可能有很多功能).

The problem is that the second template parameter of std::invoke_result_t needs a type that will be passed to a call operator of an object of a last_type type. That needs a deduction of the one before the last element's return type, and so on (there may be a lot of functions).

我最终要实现的目标是实现Java的流库(此示例等效于链接3个map函数).我还将保留其他enum,它们指示下一个元素是mapfilter还是任何其他受支持的函数,因此对于该函数应该做什么没有任何困惑-现在的问题是开始使用这种逻辑.

What I'm ultimately trying to achieve is to implement Java's stream library (this example would be the equivalent of chaining 3 map functions). I will also hold additional enums that will indicate whether the next element is a map, filter or any other supported function, so there will be no confusion about what should the function do - the problem for now is to get started with such logic.

是否有一种方法可以获取链接任意数量的函数的返回类型,而该类型将传递给已知的第一个函数?

Is there a way to obtain the return type of chaining an arbitraty number of functions, where the type passed to the very first one it known?

也许我的设计有很多缺陷,我宁愿按照完全不同的逻辑重新开始?

Or maybe my design is flawed so much that I should rather start again, following a completely different logic?

免责声明-我很了解C++20即将发布(希望如此)rangesV3.我正在尝试模仿他们的行为(有一些细微的变化).我也知道boost::adapters-它们的用法令我不满意,而且我想尝试简单地实现类似的东西.

Disclaimer - I am well aware of the upcoming in C++20 (hopefully) rangesV3. I am trying to mimic their behaviour (with some minor changes). I am also aware of boost::adapters - their usage does not satisfy me, plus I would like to try to simply implement something similar.

推荐答案

假设您有三个可调用对象f g h,并且想要获取h(g(f(args...)))的类型,可以这样做:

Say you have three callable objects f g h, and you want to get the type of h(g(f(args...))), you can do like this:

template <size_t first, class ChainedFns, class... Args>
decltype(auto) Call(ChainedFns &&fns, Args&&... args) {
    if constexpr (std::tuple_size_v<std::decay_t<ChainedFns>> == 0)
        return;
    else if constexpr (first < std::tuple_size_v<std::decay_t<ChainedFns>>-1)
        return Call<first + 1>(fns, std::invoke(std::get<first>(std::forward<ChainedFns>(fns)), std::forward<Args>(args)...));
    else if constexpr (first == std::tuple_size_v<std::decay_t<ChainedFns>>-1)
        return std::invoke(std::get<first>(std::forward<ChainedFns>(fns)), std::forward<Args>(args)...);
}

template <size_t first, class ChainedFns, class... Args>
struct invoke_result_of_chained_callables {
    using type = decltype(Call<first>(std::declval<ChainedFns>(), std::declval<Args>()...));
};

template <size_t first, class ChainedFns, class... Args>
using invoke_result_of_chained_callables_t = typename invoke_result_of_chained_callables<first, ChainedFns, Args...>::type;

int main() {
    auto fns = std::make_tuple(
        [](auto) { return 0; }, // f
        [](auto x) { return std::vector{ x }; }, // g
        [](auto x) { return x.size(); } // h
    );

    using type = decltype(Call<0>(fns, nullptr));
    static_assert(std::is_same_v<type, size_t>);

    using type1 = invoke_result_of_chained_callables_t<0, decltype(fns), std::nullptr_t>;
    static_assert(std::is_same_v<type, type1>);
    return 0;
}

此代码段也适用于任意数量的链式可调用对象.

This code snippet works for arbitrary numbers of chained callable objects too.

这篇关于我可以获取多个链接函数调用的返回类型吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆