Reputation: 20264
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?
Upvotes: 6
Views: 247
Reputation: 459
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.
Upvotes: 2
Reputation: 66200
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.
Upvotes: 2
Reputation: 49986
Sample code using tuple, as I see now it bases on other ideas from this question:
#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());
}
Upvotes: 2
Reputation: 7804
Multiple ways to achieve the same things
The best way to declare return type of function as "auto"
Upvotes: 1
Reputation: 65620
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());
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());
Upvotes: 6
Reputation: 8785
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())
Upvotes: 7
Reputation: 409176
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.
Upvotes: 9