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