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

Return several arguments for another function by a single function

本文关键字:函数 参数 返回 单个 另一个      更新时间:2023-10-16

这个问题被关闭为完全重复,因为我选择了一个误导性的问题标题。这并没有错,但提出了一个经常讨论的问题,例如在这个问题上。由于内容是关于Stackoverflow上从未涉及的更具体的主题,我希望重新打开这个问题。现在发生了这种情况,所以问题来了。

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

C++有没有办法编写另一个函数,该函数可以用作上述函数的单个参数,例如length(arguments());

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

是否可能,如果是,这在C++中怎么可能?使用 C++11 的解决方案会很好。

我认为没有任何

直接的方法可以做你想做的事情,但这里有一种 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 元函数,我们需要另一个技巧,其他帖子已经描述了这个技巧,例如在这篇文章的几个答案中。

这是转换参数数量的技巧,即 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 的函数创建另一个实现。

再次抱歉过早关闭您的问题。

附言。您需要添加以下包含语句来测试这一点:

#include <tuple>
#include <type_traits>
#include <iostream>

这是不可能的,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、宏等来进一步优化它。

我知道这仍然不是你想要的,但我认为这是最接近的方法。

你需要

声明一个struct { int a, b, c; }或类似的东西(一个类也可以工作( - 我认为你一直在编程python或php或类似的东西。

大多数编程语言都会通过某种形式的适配器函数来做到这一点。这是一个函数,它将调用的函数(此处length(和调用它的参数作为参数。您可能可以使用模板在C++中构建类似的东西。查看functional标题以获得灵感。

一种原生提供您正在寻找的语言是 Perl。你可以写:

sub arguments {
    return 1, 2, 3;
}
sub length {
    my ($p1, $p2, $p3) = @_;
    # … Work with $p1, $p2 and $p3
}
length(arguments());

通过引用传入参数,以便您可以在不返回或返回结构的情况下更改它们。只能从函数返回单个值。

我们只能返回一个值。 但是如果你想返回多个值,你可以使用数组或定义一个对象或结构

    int* arguments() {
        int x[1,4,6] 
        return x;
    };
    void length(int i[]);
    length(arguments());