【问题标题】:Is there any way to create a function that takes as argument a member function or a member?有没有办法创建一个以成员函数或成员为参数的函数?
【发布时间】:2020-02-14 01:30:47
【问题描述】:

我有这样的功能:

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 不是同一类型)

【问题讨论】:

  • 你看过 CLang API 吗?
  • 宏怎么样 :)。

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


【解决方案1】:

是的,有。一种方法是将void f 转换为函数模板,然后将指针传递给所需数据成员或成员函数的成员,然后让std::invoke(C++17,&lt;functional&gt; 标头)完成剩下的工作:

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 的好处在于它会自动处理所有成员(数据或函数)。

【讨论】:

  • 顺便说一句,我看不出f(someStream, &amp;T::getData1); f(someStream, &amp;T::m_data1);someStream &lt;&lt; Myglobal-&gt;getData1(); someStream &lt;&lt; Myglobal-&gt;m_data1; 之间的因式分解(甚至可以是someStream &lt;&lt; Myglobal-&gt;getData1() &lt;&lt; Myglobal-&gt;m_data1;);-)
  • @Jarod42 嗯...公平点:) f(someStream, &amp;T::getData1); f(someStream, &amp;T::m_data1); 是 57 个字符,someStream &lt;&lt; Myglobal-&gt;getData1() &lt;&lt; Myglobal-&gt;m_data1; 也是。至少这个解决方案不需要更多的打字。但是现在当你想在&lt;&lt;之前std::format-ing它到流...
【解决方案2】:

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

【讨论】:

  • 这太棒了!不过,人们可能只会争论可读性。在指向成员的地方购买一次,无论如何,可读性不一定是最终目标。
  • @lubgr 是的。但是,std::invoke 现在节省了很多,尤其是从(obj-&gt;*mem_function)(arg1, arg2,...) 的时代到更易读的std::invoke(mem_function, obj, std::forward&lt;Args&gt;(args)...)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-22
相关资源
最近更新 更多