Я бы хотел std::bind
к функции-члену из частного базового класса, сделанного «открытым» с помощью using
-декларация в производном классе. Вызов функции напрямую работает, но кажется, что связывание или использование указателей на функции-члены не компилируются:
#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
объект, желательно без изменения Base
или же Derived
(которые находятся в библиотеке, которой я не владею)?
Проблема здесь в том, что используя декларирование на самом деле делает:
struct Derived : private Base {
using Base::foo;
};
Это приносит Base::foo
в публичную сферу в Derived
, но это не создает совершенно новую функцию. это не эквивалентно написанию:
struct Derived : private Base {
void foo() { Base::foo(); }
}
Есть еще только Base::foo()
, используя декларирование просто влияет на правила доступа и правила разрешения перегрузки. В качестве таких &Derived::foo
действительно имеет тип void (Base::*)()
(и не void (Derived::*)()
!), так как это единственный foo
это существует. поскольку Base
является private
член доступа через указатель на Base
плохо сформирован. Я согласен, что это довольно неудачно («противоречивый» — хорошее слово).
Вы все еще можете создать объект функции, который вызывает foo
, Вы просто не можете использовать указатель на член. С C ++ 14 это становится просто, если многословно (я предполагаю произвольные аргументы здесь и void foo()
это просто упрощение проблемы)
auto d_foo = [d](auto&&... args){ return d.foo(std::forward<decltype(args)>(args)...); }
В C ++ 11 вам нужно написать тип с шаблоном с переменными значениями operator()
,
Других решений пока нет …