使用#define进行库配置

发布于 2024-10-15 03:55:51 字数 325 浏览 3 评论 0原文

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

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

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

效果很好。

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

有更好的方法吗?

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

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 compile the maths librarys and then repeat them all for their app.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

优雅的叶子 2024-10-22 03:55:51

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

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

这样,用户可以按原样使用双精度函数,但他们可以选择更改类型:

float f = sin<float>(r);

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

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.

朦胧时间 2024-10-22 03:55:51

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

或者,在 C++ 中,您可以(可能应该?)考虑使用重载或模板。 不过,我怀疑它可能会导致混乱而不是简单(或者,主要是,它将使用double重载,因为浮点文字是double 除非明确添加后缀),但模板通常是当今选择的方法。

根据 bstamour 的评论修改评论;我太保守了,有点 90 年代风格。)

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.)

蹲墙角沉默 2024-10-22 03:55:51

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

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.

尛丟丟 2024-10-22 03:55:51

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

// 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 到链接器。

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.

痴梦一场 2024-10-22 03:55:51

将条件定义放入库的头文件中(如果尚不存在),并将编译器搜索指令与其一起放入适当的 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  

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  
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文