Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get set of arguments as result of a function

Tags:

c++

c++11

I do not know the name of this pattern or even if it is exist. I need a function that return a set of arguments that would be used in another function. For example, I have this function:

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

I want to write a function like this:

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

Then call foo like this:

foo(get_arguments());

Is this possible? if yes,How?

like image 798
Humam Helfawi Avatar asked Aug 09 '16 11:08

Humam Helfawi


People also ask

How do you find the arguments passed to a function?

There are two ways to pass arguments to a function: by reference or by value. Modifying an argument that's passed by reference is reflected globally, but modifying an argument that's passed by value is reflected only inside the function.

How can you get the type of arguments passed to a function in JavaScript?

Arguments are Passed by Value The parameters, in a function call, are the function's arguments. JavaScript arguments are passed by value: The function only gets to know the values, not the argument's locations. If a function changes an argument's value, it does not change the parameter's original value.

How can you set default values for arguments of a function you are writing?

Default values indicate that the function argument will take that value if no argument value is passed during the function call. The default value is assigned by using the assignment(=) operator of the form keywordname=value.

Which keyword is used to access the array of arguments of a function in JavaScript?

You can access specific arguments by calling their index. var add = function (num1, num2) { // returns the value of `num1` console.


7 Answers

It could probably be done by using std::tuple and overloading the foo function to take a tuple and expand it to call the actual foo function.

like image 190
Some programmer dude Avatar answered Oct 15 '22 23:10

Some programmer dude


If your compiler supports future C++17 addition, you can do this by modifying get_arguments() to return std::tuple and using std::apply:

std::apply(foo, get_arguments())
like image 31
Revolver_Ocelot Avatar answered Oct 15 '22 22:10

Revolver_Ocelot


get_arguments can be implemented with std::make_tuple:

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

This will return a std::tuple<int,float,some_class>.

You can call foo with the arguments using std::experimental::apply from C++17:

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

Live Demo

There is an implementation of std::experimental::apply here if you need one.


To clean up the call, you could add a forwarding function:

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

Then you can use the syntax you desire:

foo(get_arguments());

Live Demo

like image 37
TartanLlama Avatar answered Oct 15 '22 22:10

TartanLlama


Sample code using tuple, as I see now it bases on other ideas from this question:

[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());
}
like image 29
marcinj Avatar answered Oct 15 '22 22:10

marcinj


Not exactly what you ask... but... just for fun... using std::bind and std::ref, you can call foo() using a binded bar(), in this way

#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;
 }

The output is

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

I repeat: just for fun.

like image 39
max66 Avatar answered Oct 15 '22 23:10

max66


std::tuple allows you to pack together the arguments you need for your call to foo. As others already pointed out, there are several ways you can then call your function and some of these might require a more recent standard.

In C++11, you already have std::bind which should suit your needs just fine in your case. Here's an example of how this could be achieved:

#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;
}

You can put the std::bind call into a wrapper, especially when you're using it frequently.

If you end up passing around packs of parameters back and forth, it might make sense to encapsulate them into their own data type or even a function object. This method does not need std::tuple nor std::bind and can thus be used even when you don't have access to 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;
}

This could be made more generic but this might require some template metaprogramming features introduced in C++11 and later.

like image 38
Patrik H Avatar answered Oct 16 '22 00:10

Patrik H


Multiple ways to achieve the same things

  1. Plain old C++ way : Return a structure containing multiple variables
  2. C++11 Way : use std::tuples
  3. Boost Way : Use boost::fusion

The best way to declare return type of function as "auto"

like image 40
Deepak Kr Gupta Avatar answered Oct 16 '22 00:10

Deepak Kr Gupta