Using #define to set up a library

I am working on a Maths C ++ library in which I want to be able to tune at compile time with define.

One configuration is the definition of accuracy. In code, it looks like this:

#ifdef MYMATH_USE_DOUBLE typedef double Real; #else typedef float Real; #endif 

It works great.

If someone wants to use the library after it has been configured with MYMATH_USE_DOUBLE , they must also pass this definition to the compiler.

Is there a better way to do this?

I don’t want the user to remember which definitions were used to compile the math libraries, and then repeat them all for their application.

+4
source share
5 answers

It is usually best to run the configure script, which creates a single file with all the definitions. And this file is included in all the headers. For example, if you compile OpenSSL from sources, "configure" creates e_os.h (as far as you remember the name), which is included in almost every header.

+1
source

Provide two parallel sets of functions: one for implementation using float , and another for implementation using double (and the 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 (perhaps should?) Consider using overloads or templates. My suspicion, however, is that this can lead to confusion rather than simplicity (or, basically, it will use double overloads, since double floating point literals are not explicitly specified) but templates are often the method of choice these days .

(Comments modified in the light of bstamour's comments, I was too conservative and was in the 1990s.)

+2
source

I would suggest using templates with a double default value.

 template <typename F = double> F sin(const F& r) { //... } 

Thus, users can use functions as for doubles, but they have the ability to change the type:

 float f = sin<float>(r); 

EDIT: The template system should automatically determine that F is a float in this case, although r is a float.

+2
source

Like other respondents, using templates is a possible solution to your problem. However, if you publish your generic code to users, they will have to recompile your library when choosing a different type. Perhaps it makes sense only to use the general code inside and expose your interface with a fixed set of types, using overload with a simple function:

 // 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 avoid stretching dead code when linking statically by passing -fvtable-gc -ffunction-sections -fdata-sections compiler and -Wl,--gc-sections to the linker.

+1
source

Put the conditional definition in the header files of your lin (if it does not already exist), add the search compiler directive to the corresponding lib file along it (when it will be 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 
0
source

Source: https://habr.com/ru/post/1337682/


All Articles