Реплицировать std:: function или boost:: function?
Я пытаюсь рассматривать методы класса как общие указатели функций. Из ответа намой предыдущий вопрос, связанный именно с этим, я узнал std::function
и boost::function
обеспечивают общую функциональность, необходимую мне для создания указателей на методы различных классов; если я не неправильно понял.
Теперь мне нужно знать, есть ли способ, которым я могу воспроизвести эту функциональность самостоятельно? Я не могу использовать свой компилятор C++11, застрял с C++03. Я также не могу установить Boost , так как мой инструктор не будет устанавливать Boost только для оценки моего задания.
Я бы с удовольствием повернул назад и выбрал другой подход, но я слишком далеко забрался в кроличью нору. Пожалуйста, помогите ребятам. : (2 ответа:
Можно создать указатель функции pre C++11 на функцию-член с таким объявлением:
ReturnType (ClassType::*func_ptr)() = &ClassType::function;
И вызовите его, используяэкземпляр класса с
(instance.*func_ptr)()
. Например,struct Foo { bool memberFunc() { return true; } }; int main() { typedef bool (Foo::*member_func_t)(); // Typedef member func pointer type. member_func_t func_ptr = &Foo::memberFunc; // Declare function pointer. Foo foo; // Create foo object. (foo.*func_ptr)(); // Call member func using instance. }
Есть способ воссоздать общие свойства, которые вы ищете ( я тоже читал ваш другой вопрос), Если вам нужно только создать указатели на функции-члены. Это не будет работать, если вы смешиваете указатели на функции, не являющиеся членами.
С помощью шаблонов и оболочки класс, производный от общего базового класса без шаблона можно обернуть указатель функции-члена, указывающий на функцию, которая является членом любого типа класса. Базовый класс создает общий тип, не зависящий от класса, членом которого является указатель на обернутую функцию. Это может быть полезно, если вы, например, хотите хранить обертки в одном контейнере.
Этот пример будет работать до тех пор, пока сигнатура функции всегда одинакова (в этом случае она фиксирована как
bool()
).struct func_base { virtual ~func_base() {}; virtual bool operator()() const = 0; }; template <typename C> class func_wrapper : public func_base { public: typedef bool (C::*member_func_ptr_t)(); func_wrapper(member_func_ptr_t func_ptr, C* instance_ptr) : m_func_ptr(func_ptr), m_instance_ptr(instance_ptr) {} bool operator()() const { return (m_instance_ptr->*m_func_ptr)(); } private: member_func_ptr_t m_func_ptr; C* m_instance_ptr; };
Ты можно также создать вспомогательную функцию для создания оболочек, которая автоматически выводит тип элемента.
/* This function returns a pointer to dynamically * * allocated memory and it is thus the callers * * responsibility to deallocate the memory!! */ template <typename C> func_base* make_wrapper(bool (C::*func_ptr)(), C* instance_ptr) { return new func_wrapper<C>(func_ptr, instance_ptr); }
Теперь вы можете использовать его, например, так:
struct Bar { // Define some other class with member function. bool memberFunc() { return false; } }; int main() { Foo foo; // Create object instances. Bar bar; // ----------||----------- std::deque<func_base*> d; // Deque storing pointers to base class. // Push pointer to any member func. d.push_back(make_wrapper(&Foo::memberFunc, &foo)); d.push_back(make_wrapper(&Bar::memberFunc, &bar)); for (std::deque<func_base*>::iterator it = d.begin(); it != d.end(); ++it) { (**it)(); // Call all functions in deque. } for (std::deque<func_base*>::iterator it = d.begin(); it != d.end(); ++it) { delete *it; // REMEMBER to destroy wrappers pointed to!! } }
Это будет компилироваться с компиляторами C++03. Видишь это живая демонстрация составлено с помощью gcc 4.3.2.
Примечание: Вы можете легко изменить класс-оболочку, чтобы вместо этого сохранить копию экземпляра, если вы этого хотите.
Вы должны уметь использовать функцию TR1 и связывать заголовки:
#include <tr1/functional> #include <string> #include <sstream> struct AddX { template <typename> struct result { typedef std::string type; }; std::string operator()(int a, int b) const { std::ostringstream oss; oss << (a + b); return oss.str(); } }; int main() { using namespace std::tr1; function<std::string(int)> foo = bind(AddX(), 999, placeholders::_1); return foo(1).length(); }