Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way to create a function that takes as argument a member function or a member?

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)

like image 949
Fractale Avatar asked Oct 17 '19 07:10

Fractale


People also ask

How many arguments can be passed to a function?

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)

What is the difference between arguments and Rest parameters?

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.

What are the rules for the name of a user-defined function?

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.

How to pass indefinite number of parameters to a 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.


2 Answers

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).

like image 196
lubgr Avatar answered Sep 18 '22 16:09

lubgr


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);
like image 22
JeJo Avatar answered Sep 18 '22 16:09

JeJo