我正在尝试初始化静态对象但没有成功。目的是在存储库(单例)中自动注册工厂类。
我已经看过了:How to force a static member to be initialized?
其中一条评论说(我还有一个例子):
我在C ++标准(14.7.1)中读取它:除非已经显式实例化或显式专门化了类模板或成员模板的成员,否则在引用特化时隐式实例化成员的特化。需要成员定义存在的上下文;特别是,除非静态数据成员本身以需要静态数据成员定义存在的方式使用,否则不会发生静态数据成员的初始化(以及任何相关的副作用)。
所以我试图做类似的事情,但我没有设法强制对象初始化。这是代码。我不知道我错过了什么。这是我正在使用的模板。
namespace my_lib
{
template <typename T>
struct FactoryHelper
{
FactoryHelper ();
static FactoryHelper<T> _helper;
};
}
这是库的用户用来定义工厂类的宏,同时在存储库中注册一个对象:
#define CREATE_FACTORY(ClassName)\
namespace my_lib\
{\
class ClassName##Factory;\
template<> FactoryHelper<ClassName##Factory>::FactoryHelper () { std::cout << "object initialized!" << std::endl; }\
template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper;\
struct ClassName##Factory : public FactoryBase<ClassName> {\
...\
};\
}
以前的代码在头文件(Factory.h)中定义。
在.cpp文件(Example.cpp)中,我有:
CREATE_FACTORY(UnitTestExample)
...
当我执行程序时,我看不到构造函数在调用时打印的消息。任何帮助都非常受欢迎。
提前致谢。
答案 0 :(得分:4)
这是C ++的一个棘手问题。你所做的是尝试在这里定义静态成员:
template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper;\
但这实际上是一个声明,而不是一个定义。对于C ++来说,将它视为一个定义,你必须将一些东西传递给构造函数。通常,这是您要将其初始化为的值:
template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper = FactoryHelper<ClassName##Factory>();\
但是在你的情况下,你希望这是一个单身人士,所以你可能不希望它是可复制的。在这种情况下,您需要一些虚拟参数:
template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper(0);\
你必须适当地修改你的构造函数:
template<> FactoryHelper<ClassName##Factory>::FactoryHelper (int) { std::cout << "object initialized!" << std::endl; }\
以下是完整的工作示例:
#include <iostream>
namespace my_lib
{
template<typename> struct FactoryBase { };
template <typename T>
struct FactoryHelper
{
FactoryHelper (int);
static FactoryHelper<T> _helper;
};
}
#define CREATE_FACTORY(ClassName)\
namespace my_lib\
{\
class ClassName##Factory;\
template<> FactoryHelper<ClassName##Factory>::FactoryHelper (int) { std::cout << "object initialized!" << std::endl; }\
template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper(0);\
struct ClassName##Factory : public FactoryBase<ClassName> {\
};\
}
struct UnitTestExample {
};
CREATE_FACTORY(UnitTestExample);
int main(int argc,char **argv)
{
return 0;
}
也就是说,使用其他答案中的一些建议可能是一个更好的设计决策。
有关明确专业化声明与定义的更多信息,请访问:static member initialization for specialized template class
答案 1 :(得分:1)
您的宏所做的是声明某些类成员的特化。这不会创建任何对象,也可能不是你真正想要的东西。您需要的是某处FactoryHelper<SomeClass>::_helper
的定义。静态成员的定义如下所示:
FactoryHelper<foo> FactoryHelper<foo>::_helper;
那就是说,我认为这不是最好的方法:你真正需要的只是实例化注册工厂函数的东西,这可以做得更简单,特别是没有宏。
我将如何做到这一点:
template <typename T>
struct factory_helper
{
std::auto_ptr<base> create_fuction() { return std::auto_ptr<base>(new T()); }
factory_helper(std::string const& name) {
factory.register_class(name, create_function);
}
};
这假设您要创建从类型base
派生的对象,并且您的工厂使用映射到函数对象返回std::auto_ptr<base>
作为构造函数,并且它具有register_class()
函数将名称和构造函数作为参数。然而,这些假设都不是apprach固有的:这只是为了填补你没有提到的一些空白。您可以为类foo
注册工厂函数:
static factor_helper<foo> foo_helper("foo");
答案 2 :(得分:0)
而不是静态成员(你必须创建某个地方),考虑静态变量进入静态函数的可能性,比如
namespace my_lib
{
template <typename T>
struct FactoryHelper
{
FactoryHelper () { ... };
static FactoryHelper<T>& helper()
{ static FactoryHelper<T> h; return h; }
};
}
与您要求的不一样,但不需要进行带外初始化。
答案 3 :(得分:0)
嗯,首先非常感谢建议和解释。我将你给我的解决方案添加到代码中并且没有用。然后我尝试将您的解决方案作为独立程序进行操作。
不同之处在于我正在实现的类被编译,然后作为静态库链接到可执行文件。如果我一起编译代码(不使用静态库)那么它可以工作。
我在这里找到了回复:Static initialization and destruction of a static library's globals not happening with g++
除非从主应用程序引用.o文件,否则它们不会链接。我使用了ld
选项-Wl,--whole-archive
,现在可以使用了。
-Wl,--whole-archive -lmy_static_library ... -Wl,--no-whole-archive
与第二个问题相关,我仍然不明白为什么我必须在构造函数中指定一个伪参数。
template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper(0);\
而不是这样做:
emplate<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper = FactoryHelper<ClassName##Factory>();\
谢谢!