Задача такая. Есть исходный код с примерно такой конструкцией:
...
#inlcude "mysql.h"
...
mysql_init ( &m_tMysqlDriver );
...
Захотелось отвязаться от явной связи с библиотекой и сделать динамическую загрузку. Для этого сделаны следующие изменения:
...
#include "mysql.h"
...
#if DL_MYSQL
typedef MYSQL * STDCALL (*xmysql_init)(MYSQL *mysql);
... // тут ещё 14 подобных typedef для других нужных функций
...
class CMysql...
{
...
public:
bool Init()... // грузит библиотеку; кладёт адреса нужных функций в члены-статики.
static xmysql_init m_pmysql_init;
...
};
#define sph_mysql_init (*CMysql::m_pmysql_init)
...
xmysql_init CMysql::m_pmysql_init = NULL;
...
CMysql MysqlHoder;
bool InitDynamicMysql()
{
return MysqlHoder.Init();
}
#else // !DL_MYSQL
#define sph_mysql_init mysql_init
#define InitDynamicMysql() (true)
#endif // DL_MYSQL
...
if (!InitDynamicMysql())
... // что-то пошло не так, ругаемся и вылетаем;
sph_mysql_init ( &m_tMysqlDriver );
...
В общем — ничего волшебного; обычная рутинная загрузка. Макрос DL_MYSQL определяется configure-скриптом, и позволяет задействовать старый статический вариант без накладных расходов.
Но вот с динамическим вариантом... да, всё работает. Но смущает вот это:
...
typedef MYSQL * STDCALL (*xmysql_init)(MYSQL *mysql);
...
В смысле — я залез в файл mysql.h и вытащил оттуда прототип mysql_init. Окружил имя (*x...) и получил указатель на функцию (а потом так же 14 раз для остальных использованных функций).
Выглядит коряво, нелогично и избыточно!
Возник вопрос — а нельзя ли как-нибудь объявить указатель на функцию, не цитируя явно её сигнатуру?
Т.е. у нас есть "чёрный ящик" — хедер, где объявлена функция.
Мы знаем имя нужной функции и хотим объявить указатель, в который можно положить адрес на эту функцию, и потом разыменовывать и использовать его как исходную функцию, НЕ цитируя явно её прототип из хедера.
Возможно ли такое?
Как один из вариантов смотрел на такой "велосипед":
#if DL_MYSQL
#define mysql_init (*xmysql_init)
... // другие подобные строки для других нужных функций
#include "mysql.h"
...
Получится, что нужный указатель будет объявлен прямо из хедера, за счёт подстановки стоящего перед ним #define. Но! Это уже не typedef а прямое объявление переменной. В рамках одного исходника работает, но если вынести в хедер и включить несколько раз — получаются множественные объявления.
Также не думал о возможных краевых эффектах (например, что будет, если функция используется в самом хедере, в inline-определении другой функции?).
Что подскажете, господа програмисты? Неужели такой "велосипед" — это единственный способ забороть ситуацию?