[C++] "Шаблонизация" внешного C API

procenkotanya

Допустим, вы используете сишную библиотеку с подобным API:
#ifdef __cplusplus
extern "C" {
#endif
float frob1Float(float*);
double frob1Double(double*);
float frob2Float(float*, int);
double frob2Double(double*, int);
float frob3Float(float*, int, int);
double frob3Double(double*, int, int);
#ifdef __cplusplus
}
#endif

Вы пишете шаблонную функцию template<typename T> void foo в которой T может быть float или double, и в зависимости от Т foo должна вызывать соответствующую библиотечную функцию; если это важно, foo не очень короткая, и frob* там вызываются в нескольких разных местах. Ваши действия?

okunek

template <class T> class frob
{
T frob1(...);
T frob2(...);
T frob3(...);
};
заимплементить специализации через перевызов и юзать frob

Maurog

Вы пишете шаблонную функцию template<typename T> void foo
ну такие функции обычно не пишут :grin:
обычно такие стратегии оформляются в виде traits (хотя я изначальную задачу не понял, так что телепатирую)

procenkotanya

Ок, если поменять class на struct или добавить public:, а также добавить static к объявлениям или завести экземпляр класса frob, то это будет работать. Кстати, для такого API как в условии, с равным успехом можно было бы воспользоваться перегрузкой.
Однако при таком подходе требуется несколько раз повторить плохо автоматизируемые действия: в месте специализации нужно будет добавить имена аргументов в список параметров новых функций, а потом повторить их при вызове оригинальной библиотечной функции. Нет ли способа подсократить этот механический ручной труд?

okunek

#define FROB(T) T frob(T ....) { frob##T(...); }

procenkotanya

Представь, что библиотека из условия это blas или fftw3, а функция foo их использует. Так понятно?

Maurog

Однако при таком подходе требуется несколько раз повторить плохо автоматизируемые действия: в месте специализации нужно будет добавить имена аргументов в список параметров новых функций, а потом повторить их при вызове оригинальной библиотечной функции. Нет ли способа подсократить этот механический ручной труд?
если C API нетолстое, то проще один раз руками записать. что там автоматизировать? если хочется толстое API завраппить C++, то можно и кодогенерацией заморочиться. это кстати не так сложно как многие себе представляют
либо, как выше предложили, макросами заминировать код

apl13

Представь, что библиотека из условия это blas или fftw3, а функция foo их использует. Так понятно?
Ты не поверишь, все равно traits.

procenkotanya

Умными словами все горазды трындеть. Ты код покажи!

apl13

template<typename> struct Frob {
};

#define COMMA ,

#define FROB(num, type, Type, args, decls) \
static type frob ## num(type *v decls) { \
return frob ## num ## Type(v args); \
}

#define DEF_FROB(type, Type) \
template<> struct Frob<type> { \
FROB(1, type, Type \
FROB(2, type, Type, COMMA i1, COMMA int i1) \
FROB(3, type, Type, COMMA i1 COMMA i2, COMMA int i1 COMMA int i2) \
}

DEF_FROB(double, Double);
DEF_FROB(float, Float);

#undef DEF_FROB
#undef FROB

Ты сам попросил. :D
Кстати, необходимость дублировать название типа с заглавной буквы иногда заставляет меня думать о благости подчеркиваний...

Maurog

Кстати, необходимость дублировать название типа с заглавной буквы иногда заставляет меня думать о благости подчеркиваний...
тебе нужно заставлять себя еще больше думать :grin:

procenkotanya

В условии списки аргументов разные везде, а не (type*). Как и в приведённых примерах (fftw3, blas).

apl13

Да на! :D

apl13

Я боюсь возгорания опилок! :(

okunek

между первой и второй строчкой я вставил бы ti gandon;
всех бы и вычислили

procenkotanya

Вот примерно такую загогулину я имел в виду, когда писал исходный пост.
template<class T> struct frob
{
typedef T (* const frob1_tT*);
typedef T (* const frob2_tT*, int);
typedef T (* const frob3_tT*, int, int);
static frob1_t frob1;
static frob2_t frob2;
static frob3_t frob3;
};

#define FROB_DECL(type, field, value) \
template<> frob<type>::field##_t frob<type>::field = value;

FROB_DECL(float, frob1, frob1Float)
FROB_DECL(float, frob2, frob2Float)
FROB_DECL(float, frob3, frob3Float)

FROB_DECL(double, frob1, frob1Double)
FROB_DECL(double, frob2, frob2Double)
FROB_DECL(double, frob3, frob3Double)

apl13

:jaw_drop:
Type mismatch ведь, нет?

procenkotanya

Где? Всё компилится.

apl13

Ну то есть компилится, но
шаблон, в котором вся шаблонность — статический указатель, делает мой мозг скучать. :mog:

Maurog

Вот примерно такую загогулину я имел в виду, когда писал исходный пост.
хорошая загогулина :D
Оставить комментарий
Имя или ник:
Комментарий: