Я пишу некоторую реализацию обратного вызова в C ++.
У меня есть абстрактный класс обратного вызова, скажем:
/** Abstract callback class. */
class callback {
public:
/** Executes the callback. */
void call() { do_call(); };
protected:
/** Callback call implementation specific to derived callback. */
virtual void do_call() = 0;
};
Каждый созданный мной обратный вызов (принимая функции с одним аргументом, функции с двумя аргументами ...) создается как миксин с использованием одного из следующих:
/** Makes the callback a single-argument callback. */
template <typename T>
class singleArgumentCallback {
protected:
/** Callback argument. */
T arg;
public:
/** Constructor. */
singleArgumentCallback(T arg): arg(arg) { }
};
/** Makes the callback a double-argument callback. */
template <typename T, typename V>
class doubleArgumentCallback {
protected:
/** Callback argument 1. */
T arg1;
/** Callback argument 2. */
V arg2;
public:
/** Constructor. */
doubleArgumentCallback(T arg1, V arg2): arg1(arg1), arg2(arg2) { }
};
Например, обратный вызов функции с одним аргументом будет выглядеть так:
/** Single-arg callbacks. */
template <typename T>
class singleArgFunctionCallback:
public callback,
protected singleArgumentCallback<T> {
/** Callback. */
void (*callbackMethod)(T arg);
public:
/** Constructor. */
singleArgFunctionCallback(void (*callback)(T), T argument):
singleArgumentCallback<T>(argument),
callbackMethod(callback) { }
protected:
void do_call() {
this->callbackMethod(this->arg);
}
};
Для удобства пользователя мне бы хотелось иметь метод, который создает обратный вызов без необходимости думать о деталях, чтобы можно было вызывать (к сожалению, этот интерфейс не подлежит изменению):
void test3(float x) { std::cout << x << std::endl; }
void test5(const std::string& s) { std::cout << s << std::endl; }
make_callback(&test3, 12.0f)->call();
make_callback(&test5, "oh hai!")->call();
Моя текущая реализация make_callback(...)
выглядит следующим образом:
/** Creates a callback object. */
template <typename T, typename U> callback* make_callback(
void (*callbackMethod)(T), U argument) {
return new singleArgFunctionCallback<T>(callbackMethod, argument);
}
К сожалению, когда я звоню make_callback(&test5, "oh hai!")->call();
, я получаю пустую строку в стандартном выводе. Я полагаю, что проблема заключается в том, что ссылка выходит из области видимости после инициализации обратного вызова.
Я пытался использовать указатели и ссылки, но невозможно получить указатель / ссылку на ссылку, поэтому я потерпел неудачу. Единственное решение, которое у меня было, - запретить замену ссылочного типа на T (например, T не может быть std :: string &), но это печальное решение, поскольку мне нужно создать еще один класс singleArgCallbackAcceptingReference, принимающий указатель на функцию со следующей подписью:
void (*callbackMethod)(T& arg);
Таким образом, мой код дублируется 2 ^ n раз, где n - количество аргументов функции обратного вызова.
Кто-нибудь знает обходной путь или знает, как его исправить? Заранее спасибо!