我有这样的功能:
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
不是同一类型)
答案 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
类型替换Myglobal
。 std::invoke
的好处是它可以自动处理所有成员(数据或函数)。
答案 1 :(得分:6)
@lubgr 解释了std::invoke
的用法。更进一步,您可以使用fold expression中的 c++17 将整个代码行缩减为一行。
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);