我使用静态全局变量构造函数作为方便注册函数的技巧,这个想法是这样的:
typedef int (*FuncPtr)(int);
struct RegHelper
{
RegHelper(const char * Name, FuncPtr Func)
{
Register(Name, Func);
}
}
#define REGISTER(func) RegHelper gRegHelper_ ## func (#func, func);
现在我可以这样注册函数(我用它来实现某种反射):
int Foo(int a)
{
return a * 123;
}
REGISTER(Foo)
int Bar(int a)
{
return a * 456;
}
REGISTER(Bar)
问题在于,如果我在静态库中使用它,有时链接器会检测到编译单元未被使用,并且它会丢弃整个内容。所以没有构造全局变量,并且函数没有注册......
我的问题是:我可以做些什么来解决这个问题?在初始化期间调用每个编译单元中的虚函数似乎触发了全局变量的构造,但这并不觉得非常安全。还有其他建议吗?
答案 0 :(得分:3)
要解决此问题:
我还没有找到我真正喜欢的解决方案。
答案 1 :(得分:2)
请在此处查看答案:force visual studio to link all symbols in a lib file
这个实际上对我有用。其他建议没有。
答案 2 :(得分:1)
是的,我也遇到过这个问题。我找到的唯一可靠方法是:
或:
如果你不介意使用DLLS,虽然DLL解决方案没问题,但这些都不是完美的,我也很想听听其他解决方案。
答案 3 :(得分:1)
查看"Best Way To Build a List of Per Type Data"
的答案那里有两个关键的重要概念。第一:
(void) register_object;
使用该对象来确保链接器不会将其剥离,并且
template<typename D> typename automatic_register<D>::exec_register
automatic_register<D>::register_object;
确保为每个实例分配静态全局。您应该将数据保存在此对象中。它的每个对象而不是每个类有点不同,但如果你调整你的宏来创建
// Global list of objectsh
struct FpList
{
FpList( FuncPtr func ) :
func(func)
{
head = next;
next = this
}
FpList* next;
FuncPtr func;
static FpList* head;
};
// In .cxx:
FpList* FpList::head = 0;
然后修改注册宏以便REGISTER(Foo),以便它创建:
struct register_Foo : FpList
{
register_Foo( FuncPtr fn ): FpList(fn)
{
(void) register_object;
}
static register_Foo register_object;
};
我认为这还不够。您仍然需要实例化模板,传递&amp; Foo并确保
register_Foo register_Foo::register_object
实例是在某处创建的。 automatic_register的模板代码显示了如何在标头中执行此操作。如果您可以将宏放在.cxx中,只需声明:
register_Foo register_Foo::register_object( &Foo );
作为宏的一部分。我认为它可能会奏效。 (都来自记忆,所以谁知道)。
答案 4 :(得分:1)
如果您在UNIX环境中,使用整个归档选项调用ld将强制所有目标文件包含在静态库中,而不管其是否使用。
答案 5 :(得分:1)
解决同一问题的另一种可能方案。通过函数调用获取常量值。像这样:
constant.h
const char blah[10];
extern const char *get_blah();
constant.c
#include "header.h"
const char *get_blah()
{ return blah; }
这有助于我做到这一点!