#c #c 20
#c #c 20
Вопрос:
Стандартным способом представления указателя на функцию-член для конкретного экземпляра класса является использование указателя на экземпляр и указателя на функцию-член:
void Execute(Foo* inst, void (Foo::*func)(int), int x) {
(inst->*func)(x);
}
...
Execute(foo, amp;Foo::Bar, 42);
Есть ли какой-либо способ определить Execute таким образом, чтобы указатель на функцию был представлен в виде одного выражения?
Например:
void Execute(SomeType v, int x) {
(v.inst->*v.func)(x);
}
...
Execute(foo->Bar, 42);
Моя основная проблема заключается в том, что в моем конкретном случае Foo
вложен в длинную и нестабильную цепочку пространств имен, поэтому фактический вызов с использованием стандартного синтаксиса выглядит скорее как Execute(foo, amp;hello::darkness::my::old::friend::Foo::Bar, 42)
. Однако у меня почти всегда есть локальный foo
экземпляр, из которого я могу обратиться к гораздо более простому foo->Bar(42)
. Однако мне нужно провести дополнительную бухгалтерию, поэтому мне нужно обернуть вызов чем-то вроде Execute
. using
к сожалению, директивы и псевдонимы пространства имен не являются опцией.
Комментарии:
1. Как просто указатель на член, нет. Но вы можете легко написать тип, который связывает функции-члены
2. @Human-Compiler правильно, но тогда я не могу фактически вызвать его в конкретном экземпляре. Также по-прежнему требуется указывать все пространство имен. Или вы говорите, что это можно перевести
foo->Bar
наamp;hello::darkness...::Foo::Bar
?3.Читая это снова, я, возможно, неправильно понял вопрос. Если вы хотите избежать ввода полного имени типа при попытке доступа к указателю на член, вам либо понадобится
using
псевдоним, чтобы попытаться сократить его, либо, в лучшем случае, использоватьamp;decltype(foo)::Bar
, чтобы избежать полного имени4. Я не уверен, действительно ли это возможно, но были бы вы довольны чем-то вроде
Execute(foo, Bar, 42);
?5. @Human-Compiler Я подумал, что мог бы использовать некоторую
decltype
магию, но в конечном итоге это должно выглядеть такamp;std::remove_reference<decltype(*foo)>::type::Bar
, что все еще довольно грубо. Есть ли способ скрыть эту проблему в реализации (без использования макросов)?
Ответ №1:
Есть ли какой-либо способ определить Execute таким образом, чтобы указатель на функцию был представлен в виде одного выражения?
ДА. Измените функцию на use std::function
или вызываемый параметр шаблона, например:
#include <functional>
void Execute(std::function<void(int)> v, int x)
{
v(x);
}
template<typename Callable>
void Execute(Callable v, int x)
{
v(x);
}
И затем вы можете использовать std::bind()
или лямбда-выражение для входного выражения, например:
#include <functional>
using namespace std::placeholders;
using FooType = std::remove_reference<decltype(*foo)>::type;
Execute(std::bind(amp;FooType::Bar, foo, _1), 42);
// or, in C 20 and later:
Execute(std::bind_front(amp;FooType::Bar, foo), 42);
Execute([=](int x){ foo->Bar(x); }, 42);
Кроме того, просто чтобы упомянуть, что в C Builder, в частности, есть __closure
расширение, которое позволяет вызывать методы-члены без необходимости указывать тип класса вообще, например:
typedef void (__closure *TExecuteCallable)(int);
void Execute(TExecuteCallable v, int x)
{
v(x);
}
...
Execute(foo->Bar, 42);
// or
Execute(amp;(foo->Bar), 42);
Комментарии:
1. Небольшое примечание: C 20 имеет
std::bind_front
, что предпочтительнее для тяжеловесного инструмента, которыйstd::bind
:std::bind_front(amp;FooType::Bar, foo)
2. Хотя это отвечает на вопрос, как написано в заголовке, это, похоже, не решает реальную проблему, подробно описанную в остальной части сообщения и комментариях, которая, по-видимому, не хочет полностью указывать имя типа при получении указателя функции-члена.
3. @Человек-компилятор действительно?
FooType
Псевдоним withdecltype
не решает эту проблему? Или тот факт, что лямбда-выражение вообще устраняет необходимость в этом?4. Я думаю, что, должно быть, изначально неправильно истолковал ваш ответ; не нужно защищаться. Я не понял, что
FooType
это псевдоним, и я неправильно истолковал лямбда-выражение как все еще использующее функции-члены. Мой плохой!5. @Крис добавил, спасибо. Тем не менее, лямбда-выражение обычно предпочтительнее любого использования
std::bind...()