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