我们如何在 C++ 中组合 return 多个值的函数
How do we compose functions that return multiple values in C++
我们如何在 C++ 中编写 return 多个 return 值的函数?更具体地说,如果一个函数 return 是一个元组,我们能否将这个函数与另一个不明确接受元组的函数组合起来?例如,在代码中:
#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;
}
我正在尝试组合函数 add
和 tuple_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
.
您可能想使用一些匿名的 lambda,例如
[](std::tuple <int,int> t){return add(get<0>(t),get<1>(t));}(tuple_int(1,2))
希望编译器能优化该代码。
另请参阅 currying。
您可以创建一个函数(例如 X
),它将 std::tuple <int , int >
作为参数并在内部调用 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))
您可以添加一个函数来将元组分派到参数中:
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;
我们如何在 C++ 中编写 return 多个 return 值的函数?更具体地说,如果一个函数 return 是一个元组,我们能否将这个函数与另一个不明确接受元组的函数组合起来?例如,在代码中:
#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;
}
我正在尝试组合函数 add
和 tuple_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
.
您可能想使用一些匿名的 lambda,例如
[](std::tuple <int,int> t){return add(get<0>(t),get<1>(t));}(tuple_int(1,2))
希望编译器能优化该代码。
另请参阅 currying。
您可以创建一个函数(例如 X
),它将 std::tuple <int , int >
作为参数并在内部调用 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))
您可以添加一个函数来将元组分派到参数中:
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;