由于我选择了一个误导性的问题标题,因此该问题已完全复制。这没有错,但建议经常讨论一个问题,例如:在this question。由于内容是关于Stackoverflow上从未涉及的更具体的主题,我希望重新打开该问题。现在发生了这种情况,所以这就是问题所在。
我已经给出了一个期望三个整数值作为参数length(int x, int y, int z);
的函数。我无法修改此功能,例如接受任何结构或元组作为单个参数。
C ++中是否有办法编写另一个函数,可以作为上述函数的单个参数,如length(arguments());
?
无论如何,该函数arguments();
的返回类型似乎需要int, int, int
。但据我所知,我无法在C ++中定义和使用这样的函数。我知道我可以通过arguments()
返回列表,元组,结构或类。问题已经结束,因为有些人认为我会问这个问题。但困难的部分是传递元组,结构或其他三个给定的整数参数。
这是可能的吗?如果是的话,在C ++中这怎么可能?使用C ++ 11的解决方案没问题。
答案 0 :(得分:8)
我认为没有任何直接的方法可以做你想要的,但这是我在代码的几个地方使用的C ++ 11技术。基本思想是使用我称为call_on_tuple
的模板函数来获取函数参数f
以及其他参数的元组,展开元组并在扩展列表中调用函数参数:
template <typename Fun, typename... Args, unsigned... Is>
typename std::result_of<Fun(Args...)>::type
call_on_tuple(Fun&& f, std::tuple<Args...>&& tup, indices<Is...>)
{ return f(std::get<Is>(tup)...); }
所以我的想法是,而不是调用
length(arguments());
你会打电话给
call_on_tuple(length,arguments());
这假设arguments()
已更改,因此返回std::tuple<int,int,int>
(这基本上是您引用的问题中的想法)。
现在困难的部分是如何获取Is...
参数包,这是一组用于对元组元素进行编号的整数0,1,2,...
。
如果你确定你总是有三个参数,那么你可以按字面意思使用0,1,2
,但是如果想要使这个功能适用于任何n-ary函数,我们需要另一个技巧,这已被描述通过其他帖子,例如this post的几个答案。
将参数数量(即sizeof...(Args)
)转换为整数0,1,...,sizeof...(Args)
的列表是一种技巧:
我将把这个技巧和call_on_tuple
的实现放在命名空间detail
中:
namespace detail {
template <unsigned... Is>
struct indices
{ };
template <unsigned N, unsigned... Is>
struct index_maker : index_maker<N-1,N-1,Is...>
{ };
template <unsigned... Is>
struct index_maker<0,Is...>
{ typedef indices<Is...> type; };
template <typename Fun, typename... Args, unsigned... Is>
typename std::enable_if<!std::is_void<typename std::result_of<Fun(Args...)>::type>::value,
typename std::result_of<Fun(Args...)>::type>::type
call_on_tuple(Fun&& f, std::tuple<Args...>&& tup, indices<Is...>)
{ return f(std::get<Is>(tup)...); }
}
现在,实际函数call_on_tuple
在全局命名空间中定义,如下所示:
template <typename Fun, typename... Args>
typename std::enable_if<!std::is_void<typename std::result_of<Fun(Args...)>::type>::value,
typename std::result_of<Fun(Args...)>::type>::type
call_on_tuple(Fun&& f, std::tuple<Args...>&& tup)
{
using std::tuple;
using std::forward;
using detail::index_maker;
return detail::call_on_tuple
(forward<Fun>(f),forward<tuple<Args...>>(tup),typename index_maker<sizeof...(Args)>::type());
}
它基本上调用detail::index_maker
来生成递增整数的列表,然后用它调用detail::call_on_tuple
。
因此,您可以这样做:
int length(int x, int y, int z)
{ return x + y + z; }
std::tuple<int,int,int> arguments()
{ return std::tuple<int,int,int> { 1 , 2 , 3 }; }
int main()
{
std::cout << call_on_tuple(length,arguments()) << std::endl;
return 0;
}
希望能够满足您的需求。
注意。我还添加了enable_if
以确保仅用于实际返回值的函数f
。您可以轻松地为返回void
的函数创建另一个实现。
很抱歉再次提前结束你的问题。
PS。您需要添加以下include语句来测试它:
#include <tuple>
#include <type_traits>
#include <iostream>
答案 1 :(得分:4)
这是不可能的,C ++不允许本机提供3个返回值,可以用作另一个函数的3个单独的输入参数。
但是有一些'技巧'可以返回多个值。虽然这些都不能为您的问题提供完美的解决方案,因为它们无法在不修改length()
的情况下用作length()
的单个参数。
使用容器对象,例如struct
,tuple
或class
typedef struct { int a,b,c; } myContainer;
myContainer arguments(int x, int y, int z) {
myContainer result;
result.a = 1;
// etc
return result;
}
myContainer c = arguments(x, y, z);
length(c.a, c.b, c.c);
诀窍是重载length()
函数,所以看起来你可以用一个参数:
void length(myContainer c) {
length(c.a, c.b, c.c);
}
length(arguments());
当然,您可以使用inline
,宏和其他内容进一步优化它。
我知道它仍然不是你想要的,但我认为这是最接近的方法。
答案 2 :(得分:1)
你需要声明一个struct { int a, b, c; }
或类似的东西(一个类也可以工作) - 我认为你已经编写了python或php或其他类似的东西。
答案 3 :(得分:1)
大多数编程语言都是通过某种形式的适配器功能来实现的。这是一个函数,它将调用函数(这里是length
)和调用它的参数作为参数。您可以使用模板在C ++中构建类似的东西。查看functional
标题以获取灵感。
本地提供您正在寻找的内容的语言是Perl。你可以写:
sub arguments {
return 1, 2, 3;
}
sub length {
my ($p1, $p2, $p3) = @_;
# … Work with $p1, $p2 and $p3
}
length(arguments());
答案 4 :(得分:-1)
通过引用传入参数,以便您可以更改它们而无需返回或返回结构。您只能从函数返回单个值。
答案 5 :(得分:-2)
我们只能返回一个值。但是如果要返回多个值,可以使用数组或定义对象或结构
int* arguments() {
int x[1,4,6]
return x;
};
void length(int i[]);
length(arguments());