Привязка к частной унаследованной функции-члену

Я бы хотел 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 (которые находятся в библиотеке, которой я не владею)?

6

Решение

Проблема здесь в том, что используя декларирование на самом деле делает:

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(),

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]