I have a function like this:
void f(std::ofstream& ostrm)
{
auto a = Myglobal->getData1();
ostrm << a;
auto b = Myglobal->getData2();
ostrm << b;
auto c = Myglobal->m_data1;
ostrm << c;
auto d = Myglobal->m_data2;
ostrm << d;
//...
auto z = Myglobal->getData1000();
ostrm << z;
}
Is there any way to create a function that takes as argument a member function or a member to factorize this code?
(a
, b
, c
, d and z
are not the same type)
There is no function parameter limit, so you can call a function and pass in any number of arguments, regardless of what the function declaration specifies. There are two ways that can make it possible to create a function with any number of arguments specified. Watch a video course JavaScript - The Complete Guide (Beginner + Advanced)
The arguments is an Array-like object accessible inside functions containing the values of the arguments passed to that function. The rest parameter syntax allows adding an indefinite number of arguments as an array.
Is the name of the user-defined function. Function names must comply with the rules for identifiers and must be unique within the database and to its schema. Parentheses are required after the function name even if a parameter is not specified. Is a parameter in the user-defined function.
Use the rest parameter, which has the same syntax as the spread operator to pass an indefinite number of parameters to the specified function: The difference between the arguments and the rest parameters is that all array methods can be applied directly on the rest parameters but not on the arguments.
Yes, there is. One way is to turn void f
into a function template, then pass the pointer to member of the desired data member or member function and let std::invoke
(C++17, <functional>
header) do the rest:
template <class PtrToMember>
void f(std::ofstream &ostrm, PtrToMember m){
ostrm << std::invoke(m, Myglobal);
}
// call like this:
f(someStream, &T::getData1);
f(someStream, &T::m_data1);
where you should replace T
by the the type of Myglobal
of course. The nice thing about std::invoke
is that it automatically handles all member (data or functions).
The @lubgr has explained the use of std::invoke
. One step further you can reduce the entire lines of code to a single line, using fold expression from c++17.
template<typename... Mems>
void f(std::ofstream& ostrm, Mems&&... args)
{
((ostrm << std::invoke(args, Myglobal) << " "), ...);
}
and you will pass the desired members or member functions to the function at once, instead of calling many times.
f(obj,
&MyClass::m_data1, &MyClass::m_data2, &MyClass::m_data3,
&MyClass::getData1, &MyClass::getData2, &MyClass::getData3);
(See live example)
And providing one more template parameter in the function f
(for the Class
), you can make it completely generic code and no global variables needed.
template<typename Class, typename... Mems>
void f(std::ofstream& ostrm, const Class& obj, Mems&&... args)
// ^^^^^^^^^^^^^^^^
{
((ostrm << std::invoke(args, obj) << " "), ...);
}
and now in the main()
std::ofstream ostrm{"test_file.txt"};
const auto obj{ std::make_unique<MyClass>() };
f(ostrm,
obj,
&MyClass::m_data1, &MyClass::m_data2, &MyClass::m_data3,
&MyClass::getData1, &MyClass::getData2, &MyClass::getData3);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With