Я использую библиотеку C (из C ++), которая предоставляет следующий интерфейс:
void register_callback(void* f, void* data);
void invoke_callback();
Теперь мне нужно зарегистрировать шаблон функции как обратный вызов, и это вызывает у меня проблемы. Рассмотрим следующий код:
template void my_callback(void* data) { … }
int main() {
int ft = 42;
register_callback(reinterpret_cast(&my_callback), &ft);
invoke_callback();
}
Это дает мне следующую ошибку компоновщика (с использованием g ++ (GCC) 4.5.1 в OS X , но работает с большинством других комбинаций версии компилятора / платформы ):
Не определено символы для архитектуры x86_64:
"void my_callback
(void *)", ссылка на которую имеется: _main в ccYLXc5w.o
что я нахожу понятным.
Это легко исправить путем явного создания экземпляра шаблона:
template void my_callback(void* data);
К сожалению, это не применимо в моем реальном коде, так как обратный вызов зарегистрирован внутри шаблона функции, и я не знаю, для какого набора аргументов шаблона будет вызвана эта функция, поэтому я не могу предоставить явные экземпляры для всех из них (я программирую библиотеку). Итак, мой реальный код выглядит примерно так:
template
void do_register_callback(T& value) {
register_callback(reinterpret_cast(my_callback), &value);
// Other things …
}
int main() {
int ft = 42;
do_register_callback(ft);
invoke_callback();
}
Шаблон функции неявно создается путем вызова функции. Итак, давайте сделаем это, но убедитесь, что вызов на самом деле не выполняется (функция имеет побочные эффекты):
template
void do_register_callback(T& value) {
if (false) { my_callback(0); }
register_callback(reinterpret_cast(my_callback), &value);
}
Это , похоже, работает, даже с включенной оптимизацией (так что мертвая ветка удаляется компилятором). Но я не уверен, что это когда-нибудь сломается. Я также считаю это очень уродливым решением, требующим подробного пояснительного комментария, чтобы будущий сопровождающий не удалил этот явно ненужный код.
Как мне создать экземпляр шаблона, для которого я не знаю аргументов шаблона? Очевидно, это чушь: я не могу. - Но есть ли хитрый способ обойти это?
За исключением того, мой обходной путь гарантированно будет успешным?
Код (в частности, тот факт, что я привел указатель функции к ] void *
) также выдает следующее предупреждение:
ISO C ++ запрещает приведение типов между указателем на функцию и указателем на объект
при компиляции с использованием -pedantic
. Могу ли я как-нибудь избавиться от предупреждения без написания строго типизированной оболочки C для библиотеки (что невозможно в моей ситуации)?
Запуск кода на ideone (с добавленным приведением типов) для компиляции)