Огромное спасибо за ответы!
Я сильно запутался и хочу выбрать правильную концепцию.
У меня есть около 200 тысяч строк математического кода, который интенсивно пользует lapack/blas и их различные версии.
В моей старой концепции все функции называются COPY вместо dcopy, zcopy, scopy, ccopy, и еще нескольких "своих" версий qdcopy, qzcopy (версия с четверной точностью), hdcopy, рzcopy (версия с автоматической подстановкой вместо double специальной структуры для дальнейшего использования этого всего в методах Баура-Штрассена).
Все это у меня было написано на С99, и недавно я решил таки перейти на С++, так как Бауер-Штрассен, да и все остальное, гораздо прозрачнее пишутся при использовании перегрузки операторов.
Что мне надо. У меня есть синтаксис blas/lapack, в котором имеется что-то типа
void dcopy(int N, double *X, int IX, double *Y, int IY);
но таких функций у меня много, и они называются по-разному, dcopy, zcopy, scopy, ccopy, hdcopy, hzcopy, hdcopy, hzcopy, qdcopy, qzcopy, (может и больше будет) и для каждой имеется свой вариант типов аргументов (double, float, DoubleDouble, DoubleFloat, GradDouble, GradFloat, ...)
Все также ухудшается тем, что стандартный Lapack/Blas бывает от разных производителей (intel math kernel library, netlib, embedded clapack) и эти все козлы (по другому не скажешь) слегка меняют аргументы (то int по ссылке, то как аргумент, то doublecomplex, то __complex__ double) и я хочу, чтобы все это всегда и везде работало.
Раньше так и было, но все было сделано на огромном числе #define на обычном С99, а сейчас мы приняли решение перейти на С++ и я вешаюсь, как мне это разумно сделать...
Хочу так:
#define LA(D,A) (if constexpr (std::is_same_v<D, double>) d##A; else z##A;)
inline doublecomplex *LC(__complex__ double *A) { return (doublecomplex*)A; }
inline double *LC(double *A) { return A; }
// BLAS-1
template<typename DT> inline void COPY(int N, DT *X, int IX, DT *Y, int IY) { LA(DT,copy(N, LC(X), IX, LC(Y), IY)); }
template<typename DT> inline double NRM2(int N, DT *X, int IX) { return LA(DT,nrm2(N, LC(X), IX)); }
template<typename DT> inline double NRM2_2(int N, DT *X, int IX) { DT a=LA(DT,nrm2(N, LC(X), IX)); return a*a; }
template<typename DT> inline double ASUM(int N, DT *X, int IX) { return LA(DT,asum(N, LC(X), IX)); }
template<typename DT> inline int IAMAX(int N, DT *X, int IX) { return LAI(DT,amax(N, LC(X), IX)); }
но компилятор ругается
Цитата:
g_lapack.h: In function ‘void COPY(int, DT*, int, DT*, int)’:
g_lapack.h:47:18: error: expected primary-expression before ‘if’
47 | #define LA(D,A) (if constexpr (std::is_same_v<D, double>) d##A; else z##A;)
| ^~
g_lapack.h:56:79: note: in expansion of macro ‘LA’
56 | template<typename DT> inline void COPY(int N, DT *X, int IX, DT *Y, int IY) { LA(DT,copy(N, LC(X), IX, LC(Y), IY)); }
| ^~
g_lapack.h:47:18: error: expected ‘)’ before ‘if’
47 | #define LA(D,A) (if constexpr (std::is_same_v<D, double>) d##A; else z##A;)
| ~^~
g_lapack.h:56:79: note: in expansion of macro ‘LA’
56 | template<typename DT> inline void COPY(int N, DT *X, int IX, DT *Y, int IY) { LA(DT,copy(N, LC(X), IX, LC(Y), IY)); }
| ^~
g_lapack.h:47:65: error: ‘else’ without a previous ‘if’
47 | #define LA(D,A) (if constexpr (std::is_same_v<D, double>) d##A; else z##A;)
| ^~~~
g_lapack.h:56:79: note: in expansion of macro ‘LA’
56 | template<typename DT> inline void COPY(int N, DT *X, int IX, DT *Y, int IY) { LA(DT,copy(N, LC(X), IX, LC(Y), IY)); }
| ^~
g_lapack.h:47:75: error: expected primary-expression before ‘)’ token
47 | #define LA(D,A) (if constexpr (std::is_same_v<D, double>) d##A; else z##A;)
| ^
g_lapack.h:56:79: note: in expansion of macro ‘LA’
56 | template<typename DT> inline void COPY(int N, DT *X, int IX, DT *Y, int IY) { LA(DT,copy(N, LC(X), IX, LC(Y), IY)); }
| ^~
g_lapack.h: In function ‘double NRM2(int, DT*, int)’:
g_lapack.h:47:18: error: expected primary-expression before ‘if’
47 | #define LA(D,A) (if constexpr (std::is_same_v<D, double>) d##A; else z##A;)
| ^~
Почему я хочу define? Так как я хочу измемнить однажды этот define и подставить туда ту функцию (dcopy, zcopy, qdcopy, qzcopy, gdcopy, gzcopy, etc.) что мне надо в зависимости от типа данных.
Если внутри каждой моей функции я буду писать if constexpr ... и подставлять то, что надо, то будет громоздко.
Пока я начал писать так:
- inline void COPY(int N, double *X, int IX, double *Y, int IY) { dcopy(N, X, IX, Y, IY); }
- inline void COPY(int N, __complex__ double *X, int IX, double *Y, int IY) { zcopy(N, (doublecomplex*)X, IX, (doublecomplex*)Y, IY); }
но в моем случае (8 разных типов + 4 разных поставщиков библиотек) приводит просто к уйме однотипного кода, и, вероятность опечатки тут просто растет экспоненциально.
Вдруг Вы бы смогли бы посоветовать, как, в зависимости от типа данных в template я бы мог автоматически подставлять правильный префикс в название - это бы мне очень сильно помогло!
Спасибо!