В основном у меня есть следующий класс:
class StateMachine {
...
StateMethod stateA();
StateMethod stateB();
...
};
Методы stateA () и stateB () должны иметь возможность возвращать указатели на stateA () и stateB (). Как набрать StateMethod?





Моя философия - не использовать необработанные указатели на функции-члены. Я даже не знаю, как делать то, что вы хотите, используя typedef необработанного указателя, синтаксис настолько ужасен. Мне нравится использовать boost :: function.
Это почти определенно неверно:
class X
{
public:
typedef const boost::function0<Method> Method;
// some kind of mutually recursive state machine
Method stateA()
{ return boost::bind(&X::stateB, this); }
Method stateB()
{ return boost::bind(&X::stateA, this); }
};
Эта проблема определенно намного сложнее, чем кажется на первый взгляд
Хех, я видел твой предыдущий ответ. Это, вероятно, лучший компромисс; Я обсуждал это в IRC и пришел к выводу, что typedef, ссылающийся на самого себя, вероятно, является «слишком сложной» проблемой.
Хотя, во внутреннем boost :: function0, разве вам не нужно указывать возвращаемый тип и снова использовать рекурсию?
Может быть, я не сижу за компилятором
Звучит как идеальная работа для комбинатора Y, написанного на языке метапрограммирования шаблонов.
@ 1800 ИНФОРМАЦИЯ: да, моя первая мысль была "ну, я просто напишу Y Combinator на typedefs ... о, боже. :("
Обновлено: njsf доказал, что я ошибаюсь. Однако вам может показаться, что статическое приведение проще поддерживать, поэтому остальное я оставлю здесь.
Не существует "правильного" статического типа, поскольку полный тип рекурсивен:
typedef StateMethod (StateMachine::*StateMethod)();
Лучше всего использовать typedef void (StateMachine::*StateMethod)();, а затем сделать уродливый state = (StateMethod)(this->*state)();
PS: boost::function требует явного возвращаемого типа, по крайней мере, из моего чтения документы: boost::function0<ReturnType>
Да, это подход "взломать тип-безопасность", как я уже упоминал в комментариях к вопросу. На самом деле это очень плохо. Я действительно хочу, чтобы есть способ решить эту проблему чисто. Может быть, C++ 0x предоставит способ?
Нет, на самом деле это невозможно с тщательно оцениваемой системой типов, а не только C++. Вам понадобится система типов с ленивой оценкой.
GotW # 57 говорит использовать прокси-класс с неявным преобразованием именно для этой цели.
struct StateMethod;
typedef StateMethod (StateMachine:: *FuncPtr)();
struct StateMethod
{
StateMethod( FuncPtr pp ) : p( pp ) { }
operator FuncPtr() { return p; }
FuncPtr p;
};
class StateMachine {
StateMethod stateA();
StateMethod stateB();
};
int main()
{
StateMachine *fsm = new StateMachine();
FuncPtr a = fsm->stateA(); // natural usage syntax
return 0;
}
StateMethod StateMachine::stateA
{
return stateA; // natural return syntax
}
StateMethod StateMachine::stateB
{
return stateB;
}
This solution has three main strengths:
It solves the problem as required. Better still, it's type-safe and portable.
Its machinery is transparent: You get natural syntax for the caller/user, and natural syntax for the function's own "return stateA;" statement.
It probably has zero overhead: On modern compilers, the proxy class, with its storage and functions, should inline and optimize away to nothing.
Невозможно преобразовать указатели функций-членов в обычные указатели на функции, но в остальном это круто. Должен отметить, что вы все еще просто засахариваете гипс :).
Я не занимался разработкой на C++ 5 лет и с радостью забыл об указателях на функции-члены. Да, я согласен, что это просто сахар для актеров в вашем ответе :)
Если вы измените typedef, все должно быть в порядке, правда? typedef StateMethod (StateMachine :: * FuncPtr) ();
Ах, это тот синтаксис, к которому я стремился. Спасибо!
Используя только typedef:
class StateMachine {
public:
class StateMethod;
typedef StateMethod (StateMachine::*statemethod)();
class StateMethod {
statemethod method;
StateMachine& obj;
public:
StateMethod(statemethod method_, StateMachine *obj_)
: method(method_), obj(*obj_) {}
StateMethod operator()() { return (obj.*(method))(); }
};
StateMethod stateA() { return StateMethod(&StateMachine::stateA, this); }
StateMethod stateB() { return StateMethod(&StateMachine::stateB, this); }
};
Я никогда не могу вспомнить ужасную функцию declspec C++, поэтому всякий раз, когда мне нужно узнать синтаксис, который описывает, например, функцию-член, я просто вызываю преднамеренную ошибку компилятора, которая обычно отображает правильный синтаксис для меня.
Так дано:
class StateMachine {
bool stateA(int someArg);
};
Какой синтаксис у typedef stateA? Понятия не имею ... так что давайте попробуем присвоить ему что-то несвязанное и посмотрим, что скажет компилятор:
char c = StateMachine::stateA
Компилятор говорит:
error: a value of type "bool (StateMachine::*)(int)" cannot be used to initialize
an entity of type "char"
Вот он: "bool (StateMachine :: *) (int)" - это наш typedef.
На мой взгляд, эта проблема намного сложнее, чем кажется на первый взгляд. Есть много способов решить эту проблему, если вы хотите нарушить полную безопасность типов, но в остальном ... вау.