Почему нельзя использовать разрешение области с разыменованием указателя члена?

#c #templates

Вопрос:

Рассмотрим простой пример:

 struct FooParent {
   virtual void bar() { }
};

struct Foo: FooParent {
   void bar() { }
};

int main() {
   Foo foo;
   void (Foo::*foo_member)() = amp;FooParent::bar;
   //(foo.*FooParent::foo_member)();
   foo.FooParent::bar();
}
 

Как вы можете видеть, можно использовать разрешение области foo для объекта при вызове функции-члена bar, в то время как нет способа явно объявить область для указателя функции-члена. Я согласен с тем, что синтаксис должен быть запрещен при использовании ->* , поскольку оператор может быть перегружен иногда неожиданным образом, но я не могу понять причину предотвращения явного разрешения области действия при разыменовании с. .*

Я пытаюсь отключить виртуальную отправку для указателя члена, который указывает на виртуальную функцию базового класса.

Ответ №1:

Имя переменной , которую вы объявили foo_member , находится в области действия локального блока. Это не имя Foo::foo_member , то есть у класса Foo нет члена foo_member . Напротив, имя bar находится в области действия класса Foo , а также в области действия класса FooParent .

Таким образом, механизм разрешения области действия работает так, как ожидалось: он разрешает область действия.

[Обновление:] Не существует механизма для отключения виртуальной отправки с помощью указателя функции-члена. Вы можете вызвать функцию-член базового подобъекта следующим образом:

  void (FooParent::*p)() = amp;FooParent::bar;
 (static_cast<FooParentamp;>(foo).*p)();
 

Но звонок все равно заканчивается тем, что его отправляют виртуально. Виртуальность функции-члена записывается в значение указателя функции-члена. Следующее лучшее, что вы можете сделать, — это использовать лямбду:

 auto q = [](FooParent amp; f) { f.FooParent::bar(); };
q(foo);
 

Комментарии:

1. Другими словами, причина кроется в приоритете оператора области видимости?

2. @W. F.: Вовсе нет. Причина в том, что целью разрешения области является разрешение областей, но foo_member оно уже находится в текущей области, а не в области FooParent . Так что, во всяком случае, причина, возможно, в вашем непонимании концепции «сферы охвата».

3. О, подождите, теперь я понимаю, что вы хотите сделать: вы хотите выполнить прямой вызов статической базовой функции без виртуальной отправки. Я не понял этого в твоем первоначальном вопросе. Дай мне подумать об этом.

4. @W. F.: Я полагаю, что все наоборот: функция отключения механизма виртуального вызова существует только в ограниченной форме использования явной квалификации в выражении доступа к члену класса, но не в выражениях указателя на член. (Если вы считаете, что это действительно полезная и необходимая функция, не стесняйтесь предлагать ее в качестве расширения языка.)

5. @W. F.: Если вы можете, пожалуйста, следите за тем, как часто эта конкретная проблема возникает в течение следующих, скажем, трех лет. Если вы чувствуете, что язык был бы значительно обогащен, если бы это была функция, вполне возможно предложить это в качестве расширения. В основном мы хотели бы видеть хорошие мотивирующие случаи, когда существующее решение либо невыносимо хуже, либо когда функция основного языка сделает код менее подверженным ошибкам и более понятным.