【问题标题】:How do we compose functions that return multiple values in C++ [duplicate]我们如何组合在 C++ 中返回多个值的函数 [重复]
【发布时间】:2015-03-04 02:05:08
【问题描述】:

我们如何在 C++ 中编写返回多个返回值的函数?更具体地说,如果一个函数返回一个元组,我们可以将这个函数与另一个不明确接受元组的函数组合起来吗?例如在代码中:

#include <tuple>
#include <iostream>

std::tuple <int,int> tuple_ints(int x,int y) {
    return std::tuple <int,int> (x,y);
}

int add(int x,int y) {
    return x+y;
}

int main() {
    std::cout << add(tuple_ints(1,2)) << std::endl;
}

我正在尝试编写函数addtuple_ints。这正确地产生了错误:

g++ -std=c++11 test01.cpp -o test01
test01.cpp: In function 'int main()':
test01.cpp:17:37: error: cannot convert 'std::tuple<int, int>' to 'int' for argument '1' to 'int add(int, int)'
     std::cout << add(tuple_ints(1,2)) << std::endl;
                                     ^
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1

我不想修改add 来接受一个元组;我希望定义基本上保持原样。我们还可以做些什么来组合这两个函数吗?

编辑 1

原来有提议将此功能添加到N3802 下的标准库中。这类似于@Jarod42 提供的代码。我附上了固定代码,它使用 N3802 中的代码作为参考。大多数情况下,不同之处在于提案中的代码似乎可以正确处理完美转发

#include <tuple>
#include <iostream>
#include <utility>

// This comes from N3802
template <typename F, typename Tuple, size_t... I>
decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>) {
    return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}
template <typename F, typename Tuple>
decltype(auto) apply(F&& f, Tuple&& t) {
    using Indices = 
        std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>;
    return apply_impl(std::forward<F>(f), std::forward<Tuple>(t), Indices{});
}

// Now, for our example
std::tuple <int,int> tuple_ints(int x,int y) {
    return std::tuple <int,int> (x,y);
}

int add(int x,int y) {
    return x+y;
}

int main() {
    std::cout << apply(add,tuple_ints(1,2)) << std::endl;
}

此外,如果有任何混淆,此解决方案需要 C++14 来处理 std::index_sequence 之类的内容。

【问题讨论】:

  • 我不认为你在这里编写任何函数,你是在应用它们。
  • 添加一个调用add(int,int)tuple&lt;int,int&gt; 重载有什么可怕的?这是迄今为止最简单和最易读的解决方案,而且编译器是否能够优化它是毫无疑问的。
  • @Damon:在这种情况下,是的,我可以。一般来说,我有很多这样的功能,我不想重载所有这些功能。此外,有些是用户提供的,我不想要求他们重载功能。但是,简而言之,这是一个常见的用例,我不希望将 f(X,Y,Z) 形式的每个函数都重写为 f(std::tuple &lt;X,Y,Z&gt;),以便我可以将应用程序链接在一起。
  • @Frerich Raabe:你是对的,但同样的问题出现在真正的函数组合中。大多数情况下,我只是认为上面的代码更容易看出发生了什么,并且避免了谈论如何在 C++ 中进行柯里化。而且,其实我对组合函数的应用更感兴趣。

标签: c++ c++11 c++14


【解决方案1】:

您可能想使用一些匿名 lambda,例如

  [](std::tuple <int,int> t){return add(get<0>(t),get<1>(t));}(tuple_int(1,2))

希望编译器会优化该代码。

另请阅读currying

【讨论】:

    【解决方案2】:

    您可以创建一个函数(比如X),它将std::tuple &lt;int , int &gt; 作为参数,并在内部调用int add (int x, int y)。比如:

    int X(std::tuple <int, int> t) {
        return add ( std::get<0>(t), std::get<1>(t) );
    }
    

    现在拨打X(tuple_ints(1,2))

    【讨论】:

      【解决方案3】:

      您可以添加一个函数来将元组分派到参数中:

      namespace detail
      {
          template <typename F, typename TUPLE, std::size_t...Is>
          auto call(F f, const TUPLE& t, std::index_sequence<Is...>)
          -> decltype(f(std::get<Is>(t)...))
          {
              return f(std::get<Is>(t)...);
          }
      }
      
      template <typename F, typename TUPLE>
      auto call(F f, const TUPLE& t)
      -> decltype (detail::call(f, t,
              std::make_index_sequence<std::tuple_size<TUPLE>::value>()))
      {
          return detail::call(f, t,
              std::make_index_sequence<std::tuple_size<TUPLE>::value>());
      }
      

      然后这样称呼它

      std::cout << call(add, tuple_ints(1,2)) << std::endl;
      

      Live example

      【讨论】:

        猜你喜欢
        • 2022-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-10
        • 2014-09-12
        • 2020-03-20
        • 1970-01-01
        • 2019-02-01
        相关资源
        最近更新 更多