6

我想要std::bind一个来自私有基类的成员函数,using在派生类中使用 -declaration 将其设为“公共”。直接调用该函数有效,但似乎绑定或使用成员函数指针无法编译:

#include <functional>

struct Base {
    void foo() { }
};

struct Derived : private Base { 
    using Base::foo;            
};

int main(int, char **)
{
    Derived d;

    // call member function directly:
    // compiles fine
    d.foo();

    // call function object bound to member function:
    // no matching function for call to object of type '__bind<void (Base::*)(), Derived &>'
    std::bind(&Derived::foo, d)();

    // call via pointer to member function:
    // cannot cast 'Derived' to its private base class 'Base'
    (d.*(&Derived::foo))();

    return 0;
}

查看上面的错误消息,问题似乎Derived::foo仍然只是Base::foo,我无法Base通过Derived外部访问Derived

这似乎不一致 - 我应该不能互换使用直接调用、绑定函数和函数指针吗?

是否有一种解决方法可以让我绑定到foo一个Derived对象,最好不更改BaseDerived(在我不拥有的库中)?

4

1 回答 1

4

这里的问题是using-declaration 的实际作用:

struct Derived : private Base { 
    using Base::foo;            
};

这将Base::foo在 中引入公共范围Derived,但不会创建一个全新的功能。它等于写了:

struct Derived : private Base {
    void foo() { Base::foo(); }
}

仍然只有Base::foo(). using-declaration仅影响访问规则和重载解析规则。因此&Derived::foo确实有类型void (Base::*)()(而不是void (Derived::*)()!),因为这是唯一foo存在的。由于Baseis private,通过指向的指针访问成员Base是不正确的。我同意这是非常不幸的(“不一致”是个好词)。

您仍然可以创建一个调用foo. 您只是不能使用指向成员的指针。使用 C++14,如果冗长,这将变得很简单(我在这里假设任意参数,这void foo()只是问题的简化):

auto d_foo = [d](auto&&... args){ return d.foo(std::forward<decltype(args)>(args)...); }

使用 C++11,您必须使用 variadic template 编写类型operator()

于 2016-03-28T13:49:43.013 回答