获取函数结果的参数集

时间:2016-08-09 11:11:58

标签: c++ c++11

我不知道这个模式的名称,即使它存在。我需要一个函数来返回一组将在另一个函数中使用的参数。例如,我有这个功能:

void foo(int a, float b, some_class c);

我想写一个这样的函数:

//Theoretical code:
arguments get_arguments(){
    return arguments(0,0.0f, some_class());
}

然后像这样打电话给foo

foo(get_arguments());

这可能吗?如果有,怎么样?

7 个答案:

答案 0 :(得分:9)

可以通过使用std::tuple并重载foo函数来获取元组并将其展开以调用实际的foo函数来完成。

答案 1 :(得分:7)

如果您的编译器支持将来添加C ++ 17,您可以通过修改get_arguments()以返回std::tuple并使用std::apply来执行此操作:

std::apply(foo, get_arguments())

答案 2 :(得分:6)

get_arguments可以使用std::make_tuple实现:

auto get_arguments(){
    return std::make_tuple(0,0.0f, some_class());
}

这将返回std::tuple<int,float,some_class>

您可以使用来自C ++ 17的foo的参数调用std::experimental::apply

std::experimental::apply(foo, get_arguments());

Live Demo

如果您需要,可以std::experimental::apply here实施。

要清理呼叫,您可以添加转发功能:

template <typename Tuple>
void foo(Tuple&& t) {
    return std::experimental::apply(
        static_cast<void(*)(int,float,some_class)>(&foo),
        std::forward<Tuple>(t));
}

然后你可以使用你想要的语法:

foo(get_arguments());

Live Demo

答案 3 :(得分:2)

使用元组的示例代码,正如我现在看到的那样,它基于这个问题中的其他想法:

[live]

#include <iostream>
#include <tuple>

struct some_class{};

void foo(int a, float b, some_class c) {
    std::cout << a << " " << b << "\n";
}

decltype(auto) get_arguments() {
   return std::make_tuple(0.1f, 0.2f, some_class{});
}

template<typename T>
void callFoo(const T& args)
{
  foo(std::get<0>(args), std::get<1>(args), std::get<2>(args));
}

int main()
{
    callFoo(get_arguments());
}

答案 4 :(得分:2)

不完全是你问的......但是......只是为了好玩...使用std::bindstd::ref,您可以使用绑定的foo()来呼叫bar() ,就这样

#include <tuple>
#include <complex>
#include <iostream>
#include <functional>

void foo(int a, float b, std::complex<double> c)
 { std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl; }

std::tuple<int, float, std::complex<double>> getArgs1 ()
 { return std::make_tuple(1, 22.22f, std::complex<double>{333.333, 4444.4444}); }

std::tuple<int, float, std::complex<double>> getArgs2 ()
 { return std::make_tuple(4444, 333.333f, std::complex<double>{22.22, 1.1}); }

int main()
 {

   std::tuple<int, float, std::complex<double>>  t;

   auto bar = std::bind(foo,
                        std::ref(std::get<0>(t)),
                        std::ref(std::get<1>(t)),
                        std::ref(std::get<2>(t)));

   t = getArgs1();

   bar();

   t = getArgs2();

   bar();

   return 0;
 }

输出

a = 1, b = 22.22, c = (333.333,4444.44)
a = 4444, b = 333.333, c = (22.22,1.1)

我再说一遍:只是为了好玩。

答案 5 :(得分:2)

std::tuple允许您将调用foo所需的参数打包在一起。正如其他人已经指出的那样,有几种方法可以调用你的函数,其中一些可能需要更新的标准。

在C ++ 11中,您已经拥有std::bind,在您的情况下可以满足您的需求。以下是如何实现这一目标的示例:

#include <iostream>
#include <functional>
#include <tuple>

class MyClass {};

std::tuple<int, float, MyClass> get_arguments()
{
    int a = 0;
    float b = 1.0f;
    MyClass c;
    // ... calculate parameters;
    return std::make_tuple(a, b, c);
}

void foo(int a, float b, MyClass c)
{
    std::cout << "a: " << a << ", b: " << b << "\n";
}

int main(int argc, char* argv[])
{
    // get tuple holding arguments
    auto arguments = get_arguments();

    // Binding arguments and calling directly
    std::bind(
            foo, 
            std::get<0>(arguments), 
            std::get<1>(arguments), 
            std::get<2>(arguments))();

    return 0;
}

您可以将std::bind调用放入包装器中,尤其是当您经常使用它时。

如果最终来回传递参数包,将它们封装到自己的数据类型甚至函数对象中可能是有意义的。此方法不需要std::tuple也不需要std::bind,因此即使您无法访问C ++ 11也可以使用此方法。

#include <iostream>

class MyClass {};

void foo(int a, float b, MyClass c)
{
    std::cout << "a: " << a << ", b: " << b << "\n";
}

class FooCaller
{
public:
    void operator()(void) const
    {
        foo(a, b, c);
    }

    int a;
    float b;
    MyClass c;
};

void get_arguments(FooCaller& fooCaller)
{
    // ... calculate parameters;
    fooCaller.a = 0.0f;
    fooCaller.b = 1.0f;
}


int main(int argc, char* argv[])
{
    // Create Instance and calculate/retrieve arguments
    FooCaller fooCaller;
    get_arguments(fooCaller);

    // call 'foo'
    fooCaller();
    return 0;
}

这可以更通用,但这可能需要在C ++ 11及更高版本中引入一些模板元编程功能。

答案 6 :(得分:1)

实现相同目标的多种方式

  1. 普通的旧C ++方式:返回包含多个变量的结构
  2. C ++ 11 Way:使用std :: tuples
  3. 提升方式:使用boost :: fusion
  4. 将函数的返回类型声明为&#34; auto&#34;的最佳方法