Предпосылка
Im, используя библиотеку 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 , но работает с большинством других комбинаций версии/платформы компилятора):
Undefined символы для архитектуры x86_64:
"void my_callback<int>(void*)", referenced from: _main in ccYLXc5w.o
который я считаю понятным.
Первое "решение"
Это легко фиксируется путем явного создания экземпляра шаблона:
template void my_callback<int>(void* data);
К сожалению, это не применимо в моем реальном коде, так как обратный вызов зарегистрирован внутри шаблона функции, и я не знаю, для какого набора аргументов шаблона эта функция будет вызвана, поэтому я не могу предоставить явные экземпляры для всех из них (Im программирование библиотеки). Поэтому мой настоящий код выглядит примерно так:
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 С++ запрещает кастинг между указателем на функцию и указателем на объект
при компиляции с -pedantic
. Могу ли я как-то избавиться от предупреждения, не написав строго типизированную C-оболочку для библиотеки (что невозможно в моей ситуации)?
Запуск кода на ideone (с добавленным приложением для его компиляции)