#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.: Если вы можете, пожалуйста, следите за тем, как часто эта конкретная проблема возникает в течение следующих, скажем, трех лет. Если вы чувствуете, что язык был бы значительно обогащен, если бы это была функция, вполне возможно предложить это в качестве расширения. В основном мы хотели бы видеть хорошие мотивирующие случаи, когда существующее решение либо невыносимо хуже, либо когда функция основного языка сделает код менее подверженным ошибкам и более понятным.