是否可以对所有翻译单元进行定义?
Can a define be made across all translation units?
#define 或类似的 pre-processor 定义可以跨所有翻译单元进行吗?
Header 实现对于非常小的库很有用,因为所有代码都可以包含在一个具有以下结构的 header 中并分发:
// library.h
void libFunc(); // forward decl
#ifdef IMPLEMENT_LIBRARY
int libState;
volatile int libVolState; // library state exposed to external processes
void libFunc(){
// definition
}
#endif
然而,此结构要求用户在 header 仅包含在其翻译单元之一之前定义 IMPLEMENT_LIBRARY
,这意味着它不能放入用户的 header 文件,对于不完全熟悉 C++ 编译规则的人来说可能会有点困惑。
如果有一种方法可以在所有 TU 中定义 IMPLEMENT_LIBRARY
,这可以通过
自动完成
#ifndef IMPLEMENT_LIBRARY
#defineToAllUnits IMPLEMENT_LIBRARY
// library state
// definitions
#endif
是否存在这样的机制,或者当前的 single-header 系统是否达到预期的效果?
对于这个用例,您可能根本不应该使用宏定义。如果要在库用户的 TU 中定义函数,可以使用内联函数。内联函数可以定义在多个TU中(只要定义相同):
// library.h
inline void libFunc(){
// definition
}
另一种方法是单独编译库,让库的用户 link 使用它,而不是在他们自己的 TU 中定义。
关于问题本身
Can a #define or similar pre-processor definition be made across all translation units?
可以在多个 TU 中#define 预处理器宏:
// a.cpp
#define foo a
// b.cpp
#define foo b
如果您希望定义在定义它的所有 TU 中匹配,您可以将宏定义放入头文件中,并包含:
// h.hpp
#define foo h
// a.cpp
#include "h.hpp"
// b.cpp
#include "h.hpp"
无法将一个 TU 的定义 "inject" 定义到其他 TU 中,因此没有可能等同于“#defineToAllUnits”。它 是 通常可以从编译器调用 "inject" 宏定义:gcc a.cpp b.cpp -Dfoo=h
。但是,我认为这对您的用例没有用。
一些编译单元很可能在包含 #defineToAllUnits
的单元之前编译,所以这是不可能的。
在实践中,您的问题通常通过使用构建系统将 -DIMPLEMENTAT_LIBRARY
选项传递给编译器(或等效语法)来解决。另一种可能性,在尝试使用多个定义实现广泛的可移植性时很常见,是在任何地方都包含一个配置 header,如 config.h
。 header 可以在配置时自动生成。
您还可以通过使用inline
函数和变量来避免侵犯ODR。
#define 或类似的 pre-processor 定义可以跨所有翻译单元进行吗?
Header 实现对于非常小的库很有用,因为所有代码都可以包含在一个具有以下结构的 header 中并分发:
// library.h
void libFunc(); // forward decl
#ifdef IMPLEMENT_LIBRARY
int libState;
volatile int libVolState; // library state exposed to external processes
void libFunc(){
// definition
}
#endif
然而,此结构要求用户在 header 仅包含在其翻译单元之一之前定义 IMPLEMENT_LIBRARY
,这意味着它不能放入用户的 header 文件,对于不完全熟悉 C++ 编译规则的人来说可能会有点困惑。
如果有一种方法可以在所有 TU 中定义 IMPLEMENT_LIBRARY
,这可以通过
#ifndef IMPLEMENT_LIBRARY
#defineToAllUnits IMPLEMENT_LIBRARY
// library state
// definitions
#endif
是否存在这样的机制,或者当前的 single-header 系统是否达到预期的效果?
对于这个用例,您可能根本不应该使用宏定义。如果要在库用户的 TU 中定义函数,可以使用内联函数。内联函数可以定义在多个TU中(只要定义相同):
// library.h
inline void libFunc(){
// definition
}
另一种方法是单独编译库,让库的用户 link 使用它,而不是在他们自己的 TU 中定义。
关于问题本身
Can a #define or similar pre-processor definition be made across all translation units?
可以在多个 TU 中#define 预处理器宏:
// a.cpp
#define foo a
// b.cpp
#define foo b
如果您希望定义在定义它的所有 TU 中匹配,您可以将宏定义放入头文件中,并包含:
// h.hpp
#define foo h
// a.cpp
#include "h.hpp"
// b.cpp
#include "h.hpp"
无法将一个 TU 的定义 "inject" 定义到其他 TU 中,因此没有可能等同于“#defineToAllUnits”。它 是 通常可以从编译器调用 "inject" 宏定义:gcc a.cpp b.cpp -Dfoo=h
。但是,我认为这对您的用例没有用。
一些编译单元很可能在包含 #defineToAllUnits
的单元之前编译,所以这是不可能的。
在实践中,您的问题通常通过使用构建系统将 -DIMPLEMENTAT_LIBRARY
选项传递给编译器(或等效语法)来解决。另一种可能性,在尝试使用多个定义实现广泛的可移植性时很常见,是在任何地方都包含一个配置 header,如 config.h
。 header 可以在配置时自动生成。
您还可以通过使用inline
函数和变量来避免侵犯ODR。