使用#define进行库配置

时间:2011-01-30 18:04:48

标签: c++ c-preprocessor

我正在使用C ++数学库,我希望能够在编译时使用定义进行配置。

其中一个配置是定义精度。在代码中它看起来像这样:

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

工作正常。

如果有人想在使用MYMATH_USE_DOUBLE配置库后再使用该库,那么他们也必须将该定义传递给编译器。

有更好的方法吗?

我不希望用户必须记住用于编译数学库的定义,然后为他们的应用重复所有定义。

5 个答案:

答案 0 :(得分:2)

提供两组并行的函数,一组用于使用float实现,另一组用于使用double实现(以及第三项用于long double)。这就是C库的作用 - sin()doublesinf()floatsinl()long double

或者,在C ++中,你可以(可能应该?)考虑使用重载或模板。 我怀疑那是它可能导致混淆而不是简单(或者,由于浮点文字是double,它会使用double重载。显式后缀),但模板通常是目前选择的方法。

评论根据bstamour的评论进行了修改;我过于保守,而且是90年代。

答案 1 :(得分:2)

我建议使用模板,默认为double。

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

这样用户可以按原样使用这些功能,但是他们可以选择更改类型:

float f = sin<float>(r);

编辑:模板系统应该在这种情况下自动推断F是浮点数,但是r是浮点数。

答案 2 :(得分:1)

通常,最佳做法是运行“configure”脚本,该脚本创建一个包含所有定义的文件。此文件包含在所有标头中。例如,如果从源代码编译OpenSSL,“configure”会创建e_os.h(记住名称),实际上包含在每个头文件中。

答案 3 :(得分:1)

正如其他人已经建议的那样,使用模板可以解决您的问题。但是,如果将通用代码公开给用户,则在选择其他类型时,他们必须重新编译库。在内部仅使用通用代码并使用普通函数重载将接口暴露给一组固定类型可能更有意义:

// 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); }

假设使用GNU工具链,通过将-fvtable-gc -ffunction-sections -fdata-sections传递给编译器并将-Wl,--gc-sections传递给链接器,您应该能够避免在静态链接时引入死代码。

答案 4 :(得分:0)

将条件定义放在你的lin的头文件中(如果它还没有),并将一个编译器搜索指令放在它的适当的lib文件中(当它包含在客户端时)。

#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