【问题标题】:Return several arguments for another function by a single function通过单个函数返回另一个函数的多个参数
【发布时间】:2012-12-14 21:45:57
【问题描述】:

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

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

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

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

这可能吗?如果可以,在 C++ 中怎么可能?使用 C++11 的解决方案就可以了。

【问题讨论】:

  • 现在每个问题都是重复的。 . .
  • 有人在没有评论的情况下投了反对票,无论如何你可以使用对象或结构来做到这一点
  • @jogojapan 是的,你是对的。

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


【解决方案1】:

我认为没有任何直接的方法可以做你想做的事,但这是我在代码的几个地方使用的 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&lt;int,int,int&gt;(这基本上是您引用的问题的想法)。

现在困难的部分是如何获取Is... 参数包,它是一个整数包0,1,2,...,用于对元组的元素进行编号。

如果你确定你总是有三个参数,你可以使用 0,1,2帖子,例如在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 <tuple>
#include <type_traits>
#include <iostream>

【讨论】:

  • 感谢您分享您的想法和代码。我什至可以使用您的方法的修改版本来简化我的实现的其他一些逻辑。
【解决方案2】:

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

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

【讨论】:

  • 很抱歉我的表述不清楚,但我无法修改length 函数。我已经更新了我的问题以明确这一点。
  • @sharethis 我再次更新了我的答案。使用函数重载你可以fake单参数长度函数...
  • 重载也是解决这个问题的一种很好且简单(!)的方法。由于jogojapan的回答对我有更多帮助,因此我给了您一个赞成票。但我猜这是具体情况。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

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

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

    【讨论】:

      【解决方案5】:

      通过引用传递参数,这样您就可以在不返回或返回结构的情况下更改它们。一个函数只能返回一个值。

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

          猜你喜欢
          • 2011-07-14
          • 2016-09-02
          • 1970-01-01
          • 1970-01-01
          • 2021-04-10
          • 1970-01-01
          • 1970-01-01
          • 2010-09-15
          • 2020-12-26
          相关资源
          最近更新 更多