有什么方法可以创建以成员函数或成员作为参数的函数?

时间:2019-10-17 07:38:48

标签: c++ templates c++17 member member-functions

我有这样的功能:

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

有什么方法可以创建将成员函数成员作为参数分解为参数的函数?

({abc,d和z不是同一类型)

2 个答案:

答案 0 :(得分:7)

是的,有。一种方法是将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类型替换Myglobalstd::invoke的好处是它可以自动处理所有成员(数据或函数)。

答案 1 :(得分:6)

@lubgr 解释了std::invoke的用法。更进一步,您可以使用fold expression中的 将整个代码行缩减为一行。

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

See live example


并在函数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);