Есть ли способ создать функцию, которая принимает в качестве аргумента функцию-член или член? - PullRequest
7 голосов
/ 17 октября 2019

У меня есть такая функция:

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

Есть ли способ создать функцию, которая принимает в качестве аргумента функцию-члена или член дляфакторизовать этот код?

(a, b, c, d и z не одного типа)

Ответы [ 2 ]

7 голосов
/ 17 октября 2019

Да, есть. Один из способов - превратить void f в шаблон функции, затем передать указатель на член нужного элемента данных или функцию-член и позволить std::invoke (заголовок C ++ 17, <functional>) сделатьостальные:

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

, где вы должны заменить T на тип Myglobal, конечно. Приятной особенностью std::invoke является то, что он автоматически обрабатывает все элементы (данные или функции).

6 голосов
/ 17 октября 2019

@ lubgr объясняет использование std::invoke. Еще одним шагом вы можете сократить все строки кода до одной строки, используя сложенное выражение из .

template<typename... Mems>
void f(std::ofstream& ostrm, Mems&&... args)
{
    ((ostrm << std::invoke(args, Myglobal) << " "), ...);
}

и вы передадите нужные функции или функции-члены в функцию сразу, а не вызовете ее много раз.

f(obj,
    &MyClass::m_data1, &MyClass::m_data2, &MyClass::m_data3,
    &MyClass::getData1, &MyClass::getData2, &MyClass::getData3);

( См. Пример в реальном времени )


И, предоставив еще один параметр шаблона в функции f (для Class), вы можете сделать его полностью универсальным кодом и не требовать глобальных переменных.

template<typename Class, typename... Mems>
void f(std::ofstream& ostrm, const Class& obj, Mems&&... args)
//                           ^^^^^^^^^^^^^^^^
{
    ((ostrm << std::invoke(args, obj) << " "), ...);
}

а теперь в 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);
...