通过单个函数返回另一个函数的几个参数

时间:2012-12-30 09:21:02

标签: c++ function syntax c++11 arguments

由于我选择了一个误导性的问题标题,因此该问题已完全复制。这没有错,但建议经常讨论一个问题,例如:在this question。由于内容是关于Stackoverflow上从未涉及的更具体的主题,我希望重新打开该问题。现在发生了这种情况,所以这就是问题所在。

我已经给出了一个期望三个整数值作为参数length(int x, int y, int z);的函数。我无法修改此功能,例如接受任何结构或元组作为单个参数。

C ++中是否有办法编写另一个函数,可以作为上述函数的单个参数,如length(arguments());

无论如何,该函数arguments();的返回类型似乎需要int, int, int。但据我所知,我无法在C ++中定义和使用这样的函数。我知道我可以通过arguments()返回列表,元组,结构或类。问题已经结束,因为有些人认为我会问这个问题。但困难的部分是传递元组,结构或其他三个给定的整数参数。

这是可能的吗?如果是的话,在C ++中这怎么可能?使用C ++ 11的解决方案没问题。

6 个答案:

答案 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()的单个参数。

使用容器对象,例如structtupleclass

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());