引用对象方法

Reference to object method

我想引用对象方法的调用。这在 C++ 中可能吗?我应该搜索的技术名称是什么?我们可以提供一些具有预定值的参数吗?

下面的代码突出显示了我想使用的内容

struct Foo {
  void barNoArgs();
  void barMultArgs(int, float, bool);
};

Foo f;

auto& refToBarNoArgs = f.barNoArgs;
refToBarNoArgs(); // should call f.barNoArgs()


auto& refToBarMultArgs = f.barMultArgs(?, 3.14f, ?);
refToBarNoArgs(42, true); // should call f.barMultArgs(42, 3.14f, true)

What is the technical name I should be searching for?

这称为参数绑定,有时也称为部分函数

但首先,您应该知道您的两个示例都是完全相同的问题。毕竟,方法本质上是带有隐藏的第一个参数 this 的函数。

所以 refToBarNoArgs 是一个带 0 个参数的函数,它调用 Foo::barNoArgs 第一个参数 pre-populated。 refToBarNoArgs 是一个接受两个参数的函数,并使用第一个和第三个参数 pre-populated 调用 Foo::barMultArgs,并使用自己的参数调用第二个和第四个。

这里的关键点是您的“引用”不能是 C++ 术语意义上的引用。引用实际上并不存在(因为没有与引用本身关联的对象)。在这两种情况下,我们都需要存储 pre-populated 参数的值,并管理它们的生命周期。它必须是一个实际的对象,具有存储和生命周期,并且表现得像一个函数。这称为 Functor.

该语言为我们提供了一点方便的语法糖,以方便同时创建此类仿函数的类型和单个实例:Lambdas。

auto refToBarNoArgs = [&f](){f.barNoArgs();};
refToBarNoArgs();

auto refToBarMultArgs = [&f](int i, bool b){f.barMultArgs(i, 3.14f, b);};
refToBarNoArgs(42, true);

如果您不熟悉 lambda,请注意我示例中的 [&f]。这意味着 lambda 通过引用捕获 f。正因为如此,它们的生存期(例如,存储在 std::function<> 中)不应超过 f.

的生命周期

您也可以使用 std::bind 来获得同样的效果。事实上,最终结果与您的原始代码非常接近:

#include <functional>

struct Foo {
  void barNoArgs();
  void barMultArgs(int, float, bool);
};

int main() {
    using namespace std::placeholders;  // for _1, _2, _3...
    Foo f;

    auto refToBarNoArgs = std::bind(&Foo::barNoArgs, &f);
    refToBarNoArgs();

    auto refToBarMultArgs = std::bind(&Foo::barMultArgs, &f, _1, 3.14f, _2);
    refToBarNoArgs(42, true);
}

就个人而言,我发现 lambda 更清晰。

从技术上讲,您可以获得指向成员函数的指针(成员函数指针),然后为对象调用该函数。

struct Foo {
  void barNoArgs();
  void barMultArgs(int, float, bool);
};

void foo() {
    Foo f;

    auto refToBarNoArgs = &Foo::barNoArgs;
    (f.*refToBarNoArgs)();
}

修复(绑定)参数以创建一个新函数,然后您可以使用缺少的参数调用该函数更具挑战性。恕我直言,最简单的方法是使用 lambda 函数创建一个未命名的函数来包装成员并捕获对象。另一种方法是使用 std::bind.

#include <functional> // for std::bind

struct Foo {
  void barNoArgs();
  void barMultArgs(int, float, bool);
};

void foo() {
    using namespace std;
    using namespace std::placeholders;

    Foo f;

    auto b = bind( &Foo::barMultArgs, f, _1, 3.14f, _2);
    auto l = [&f](auto const& x, auto const& y) {return f.barMultArgs(x,3.14f,y);};

    b(42, true); // should call f.barMultArgs(42, 3.14f, true)
    l(42, true); // should call f.barMultArgs(42, 3.14f, true)
}