Using #define for library configuration
I'm working on a C++ maths library in which I want to be able to configure at compile time using defines.
One of the configurations is defining the precision. In code it looks like this:
#ifdef MYMATH_USE_DOUBLE
typedef double Real;
#else
typedef float Real;
#endif
That works fine.
If someone wants to then use the library after it has been configured with MYMATH_USE_DOUBLE
they'll have to also pass that define to the compiler.
Is there a better way of doing this?
I don't want the user to have to remember what defines were used to compil开发者_JS百科e the maths librarys and then repeat them all for their app.
I would suggest using templates, with double as default.
template <typename F = double>
F sin(const F& r)
{
//...
}
That way users can use the functions as is for doubles, but they have the option of changing the type:
float f = sin<float>(r);
EDIT: The template system should auto-infer that F is a float in this case though, given r is a float.
Provide two parallel sets of functions, one for the implementation using float
and the other for the implementation using double
(and a third for long double
). This is what the C library does - there is sin()
for double
, sinf()
for float
, and sinl()
for long double
.
Or, in C++, you could (probably should?) consider using overloads or templates. My suspicion is, though, that that It might lead to confusion rather than simplicity (or, preponderantly, it will use the double
overloads since floating-point literals are double
unless suffixed explicitly), but templates are often the method of choice these days.
(Comments modified in the light of comments by bstamour; I was being too conservative and 1990s-ish.)
Usually, the best practice is to run "configure" script, that creates one file with all defines. And this file is included in all headers. For example, if you compile OpenSSL from sources, "configure" creates e_os.h (as far as a remember the name), that is included practically in every header.
As others already sugggested, using templates is a possible solution to your problem. However, if you expose your generic code to users, they'll have to recompile your library when choosing a different type. It might make more sense to only use generic code internally and expose your interface with a fixed set of types using plain-old function overloading:
// generic implementation (internal linkage):
namespace {
template<typename Real>
Real plus42(Real value) {
return value + 42;
}
}
// API functions (external linkage):
float plus42(float value) { return plus42<>(value); }
double plus42(double value) { return plus42<>(value); }
Assuming the GNU toolchain, you should be able to avoid pulling in dead code when linking statically by passing -fvtable-gc -ffunction-sections -fdata-sections
to the compiler and -Wl,--gc-sections
to the linker.
Put the conditional define in the header files of your library (if it's not already there) and place a compiler-search directive in the appropriate lib-file along with it (when it's included by clients).
#ifdef MYMATH_USE_DOUBLE
typedef double Real;
$ifndef _LIB // only for clients
#pragma comment( lib, "double_lib" ) // double_lib name of the library.
#endif
#else
typedef float Real;
$ifndef _LIB
#pragma comment( lib, "float_lib" )
#endif
#endif
精彩评论