I am trying to initialize a static object without success. The purpose is to automatically register a factory class in a repository (which is a singleton).
I've already had a look at: How to force a static member to be initialized?
One of the comments says that (there is also an example that I've followed):
I read it up in the C++ standard (14.7.1): Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
So I'm trying to do something similar but I haven't manage to force the object initialization. Here is the code. I don't know what I'm missing. This is the template I'm using.
namespace my_lib
{
template <typename T>
struct FactoryHelper
{
FactoryHelper ();
static FactoryHelper<T> _helper;
};
}
And this is the macro that the user of the library would use to define the factory class and, at the same time, register an object in the repository:
#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> {\
...\
};\
}
The previous code is defined in a header file (Factory.h).
In a .cpp file (Example.cpp), I have:
CREATE_FACTORY(UnitTestExample)
...
When I execute the program, I cannot see the message that the constructor prints when it is invoked. Any help is more than welcome.
Thanks in advance.
This is a tricky area of C++. What you've done is to try to define the static member here:
template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper;\
but this is actually a declaration and not a definition. For C++ to treat it as a definition you have to pass something to the constructor. Typically, this is the value you want to initialize it to:
template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper = FactoryHelper<ClassName##Factory>();\
But in your case, you want this to be a singleton, so you probably don't want it to be copyable. In that case, you need some dummy parameter:
template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper(0);\
and you have to modify your constructor appropriately:
template<> FactoryHelper<ClassName##Factory>::FactoryHelper (int) { std::cout << "object initialized!" << std::endl; }\
Here is the complete working example:
#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;
}
That said, using some of the suggestions in the other answers may be a better design decision.
More information on the explicit specialization declaration vs. definition can be found here: static member initialization for specialized template class
What your macro does is to declare a specializations of some members of a class. This won't create any object and probably not what you really want anyway. What you'd need is a definition of FactoryHelper<SomeClass>::_helper somewhere. A definition of the static member would look something like this:
FactoryHelper<foo> FactoryHelper<foo>::_helper;
That said, I don't think the is the the way to go at all: all you really need is to instantiate something which registers a factory function and this can be done much simpler and, especially, without macros.
Here is how I would do this:
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);
}
};
This assumes that you want to create objects derived from type base and that your factory uses a mapping to function object returning std::auto_ptr<base> as constructor functions and that it has a register_class() function which takes the name and the constructor function as parameters. Neither of these assumptions is inherent to the apprach, though: this is just to fill in some of the blanks you didn't mention. You would register a factory function for a class foo something like this:
static factor_helper<foo> foo_helper("foo");
Instead of a static member (you have to create somewhere), consider the possibility of a static variable into a static function, like
namespace my_lib
{
template <typename T>
struct FactoryHelper
{
FactoryHelper () { ... };
static FactoryHelper<T>& helper()
{ static FactoryHelper<T> h; return h; }
};
}
Not the same as you are asking, but no need of out-of-band initializations.
Well, first of all thanks a lot for both the suggestions and the explanations. I added the solutions you gave me to the code and didn't work. Then I tried your solutions as stand-alone programs and worked.
The difference is that the classes I'm implementing are compiled and then linked to the executable as a static libraries. If I compile the code all together (without using static libraries) then it works.
I found the response here: Static initialization and destruction of a static library's globals not happening with g++
The .o files are not linked unless they are referenced from the main application. I have used the ld option -Wl,--whole-archive and now it works.
-Wl,--whole-archive -lmy_static_library ... -Wl,--no-whole-archive
Related to the second question, I still don't understand why I have to specify a dummy parameter in the constructor.
template<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper(0);\
Rather than doing this:
emplate<> FactoryHelper<ClassName##Factory> FactoryHelper<ClassName##Factory>::_helper = FactoryHelper<ClassName##Factory>();\
Thanks!
Related
I want to add a static function to a template class that is accessible without passing template parameters first. Is that possible?
namespace foo {
template <typename T>
class bar {
public:
static void eggs();
};
}
foo::bar<some_t>::eggs(); // works
foo::bar::eggs(); // does not work
I would like to avoid moving eggs() to the foo namespace or to create a new namespace for it (eg. foo::bar_::eggs(), ugh).
No. That is not how template classes work. What you want to do is not possible in C++.
Remember that foo::bar does not name any type, but solely a template that can be used to create other types.
Besides using typedefs/type aliases (through using), you can perhaps have a non-templated base class for you templates, and then put your static members there. If you use public inheritance, changing the static member in any of the templated classes will change in all of them.
After experimenting with your code:
I want to add a static function to a template class that is accessible
without passing template parameters first. Is that possible?
namespace foo {
template <typename T>
class bar {
public:
static void eggs();
};
}
foo::bar<some_t>::eggs(); // works
foo::bar::eggs(); // does not work
I would like to avoid moving eggs() to the foo namespace or to create
a new namespace for it (eg. foo::bar_::eggs(), ugh).
I have come to the conclusion that, the first instance of
foo::bar<some_t>::eggs(); // works while
foo::bar::eggs(); // doesn't
Is due to the fact that when working with templates, anything within the class has to be relative to a specific object, even if you do not want the function to be. I even tried using function pointers and tried to save them to template class and without no avail I couldn't even get that to compile. I do not see much of an option for you in this situation. There maybe other tricks out there that someone might know, but not from what I can see.
You can make the template parameter optional and you can define a specialized template. Like this:
namespace foo {
template <typename T = void> class bar {
public:
static void eggs() { cout << "First there was the egg" << endl; }
};
template <> class bar<void> {
public:
static void eggs() {
cout << "Then there was the chicken... or was it?" << endl;
}
};
}
auto main() -> int {
foo::bar<int>::eggs(); // egg
foo::bar<>::eggs(); // chicken
return 0;
}
I'm designing a wrapper over various computational functionality. Some of the underlying backends require some init functions to be called before any other API calls are made. I could use some static variable that is initialized before main, and wrap it in some function as described here so that I can catch any errors produced during initialization.
I wonder if there is a better way to handle this. Note that there will never be an instance of the class template, as everything is either a typedef or static member.
To address the problem of initializing the API only for some specializations, and of initializing it only once, I'd do something like this:
#include <iostream>
template <typename T>
struct Wrapper
{
// class who will be statically instantiated
struct CtorClass
{
CtorClass()
{
std::cout << "Init\n";
}
};
static CtorClass static_ctor;
static void compute1(){}
static void compute2(){}
};
// definition for template static member cons
template <typename T>
typename Wrapper<T>::CtorClass Wrapper<T>::static_ctor;
struct NeedInit{};
// you will have to use static_ctor in every funcition of the
template <>
void Wrapper<NeedInit>::compute1()
{
static_ctor;
}
template <>
void Wrapper<NeedInit>::compute2()
{
static_ctor;
}
int main()
{
Wrapper<int>::compute1();
Wrapper<int>::compute2();
Wrapper<NeedInit>::compute1();
Wrapper<NeedInit>::compute2();
}
Sadly, this way you have to use static_ctor in every function specialization that belongs to a Wrapper<NeedInit> class. But you wouldn't need to check for the initialization to have already been called.
Then, you could catch errors like you said.
I have the following code (it's on ideone.com):
template<class T>
class CMemoryPool
{
public:
CMemoryPool(int param1)
: stuff(param1)
{}
private:
T stuff;
};
template<class T>
class CList
{
public:
struct Entry
{
T data;
};
static CMemoryPool<Entry> s_pool;
};
template<class T>
CList<T>::CMemoryPool<CList<T>::Entry>::s_pool(1);
int main()
{
CList<int> list;
}
I can't seem to get the initialization of s_pool outside of the class to compile. Can anyone help me figure out how to make this work? Note I'm using C++03 only.
I think that you forgot how initializing a static data member works in general:
struct Data { int i; };
struct Holder { static Data StaticMember; };
Data Holder::StaticMember = { 1 };
^ ^~~~~~~~~~~~~~~~~~~~ static member qualified name
\~~~ static member type
If you look at your declaration, it is striking that you forgot one of the two above:
// Only a single element: there should be a type and a name
template<class T>
CList<T>::template CMemoryPool<typename CList<T>::Entry>::s_pool(1);
// Two elements
template<class T>
CMemoryPool<typename CList<T>::Entry> CList<T>::s_pool(1);
^ ^~~~~~~~~~~~~~~~ name
\~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ type
Once corrected it just works
EDIT:
I was under the impression that:
You must explicitly give value to the static value for each instantiation of the template:
CList<int>::CMemoryPool<CList<int>::Entry>::s_pool(1);
must be somewhere in your *.C files...
Alternatively, use a static local variable in a method of the table used to get the value.
But after playing a bit, this seems to compile in ideone
template<class T>
CMemoryPool<typename CList<T>::Entry> CList<T>::s_pool(1);
I still recommend #FredOverflow solution as it protects your from static initialization problems
Static data members inside class templates are somewhat of a pain to initialize. I suggest a factory function instead. Then you don't need to worry about defining the variable somewhere else.
Just rewrite the line
static CMemoryPool<Entry> s_pool;
to
static CMemoryPool<Entry>& s_pool()
{
static CMemoryPool<Entry> foobar;
return foobar;
}
And then use s_pool() instead s_pool everywhere. You get lazy initialization as a benefit.
I'm trying to build a wrapper around a managed class so I can call it from native code.
Here is the managed function :
void MyManagedFunction(MyStruct iStruct)
{
// Code according to what are the types of the 2 MyStruct members
}
struct MyStruct
{
public MyStruct(Object iValue1, Object iValue2) : this()
{
Value1 = iValue1; // Often contains DateTime::Now
Value2 = iValue2;
}
public Object Value1;
public Object Value2;
}
In my case, Value1 will almost always be System::DateTime::Now and the Value2 will almost always be a common data type (int, double, float, string, bool). I thought of making two templated function in the wrapper.
In the wrapper's .h I have the following :
#ifdef MYWRAPPER_EXPORTS
# define MYWRAPPER __declspec(dllexport)
#else
# define MYWRAPPER __declspec(dllimport)
#endif
class MYWRAPPER MyWrapper
{
public:
MyWrapper();
~MyWrapper();
template <class T> void MyNativeFunction(T iParam1)
{
MyStruct^ wStruct = gcnew MyStruct(System::DateTime::Now, iParam1);
//The class containing the managed function is a singleton
MyManagedClass::Instance->MyManagedFunction(wStruct);
}
template <class T, class W> void MyNativeFunction(T iParam1, W iParam2)
{
MyStruct^ wStruct = gcnew MyStruct(iParam1, iParam2);
//The class containing the managed function is a singleton
MyManagedClass::Instance->MyManagedFunction(wStruct);
}
};
This wrapper compiled without problem. The problem obviously occurred when I included the .h in the purely native code. Since I can't hide the content of the templated function, I have managed stuff visible on the native side which prevent the native code from compiling.
I was wondering if there was a workaround in order to achieve this. I don't mind if I'm limited into using only primitive types as parameters for the function. The best thing is if I was able to simply hide the content of the templated function in the native code so it only knows about the signature
Here's what I've tried/considered so far :
Converting the parameters to void* and call a function in which would call the managed one. By doing so, I can't cast the void* back to an object since I lose its type and using typeid to get the 'T' or 'W' type doesn't help since it vary from a compiler to another.
Overloading the function for every types I want to use. This is what I'll most likely use if I doesn't find a better solution. The problem is it means alot of overloading (especially for the 2 parameters function considering the number of combination)
If you know all the types your template will take, you can force instantiate it with those variables and thus put the code for the template functions in the source file instead of a header.
You can look at the example provided in Storing C++ template function definitions in a .CPP file
As he says you can do as below (copy-paste alert):
.h file
class foo
{
public:
template <typename T>
void do(const T& t);
};
.cpp file
template <typename T>
void foo::do(const T& t)
{
// Do something with t
}
template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);
Why does following code raise an exception (in createObjects call to map::at)
alternativly the code (and its output) can be viewed here
intererestingly the code works as expected if the commented lines are uncommented with both microsoft and gcc compiler (see here), this even works with initMap as ordinary static variable instead of static getter.
The only reason for this i can think of is that the order of initialization of the static registerHelper_ object (factory_helper_)and the std::map object (initMap) are wrong, however i cant see how that could happen, because the map object is constructed on first usage and thats in factory_helper_ constructor, so everything should be alright shouldnt it ?
I am even more suprised that those doNothing() lines fix the issue, because that call to doNothing() would happen after the critical section (which currently fails) is passed anyway.
EDIT: debugging showed, that without the call to factory_helper_.doNothing(), the constructor of factory_helper_ is never called.
#include <iostream>
#include <string>
#include <map>
#define FACTORY_CLASS(classtype) \
extern const char classtype##_name_[] = #classtype; \
class classtype : FactoryBase<classtype,classtype##_name_>
namespace detail_
{
class registerHelperBase
{
public:
registerHelperBase(){}
protected:
static std::map<std::string, void * (*)(void)>& getInitMap() {
static std::map<std::string, void * (*)(void)>* initMap = 0;
if(!initMap)
initMap= new std::map<std::string, void * (*)(void)>();
return *initMap;
}
};
template<class TParent, const char* ClassName>
class registerHelper_ : registerHelperBase {
static registerHelper_ help_;
public:
//void doNothing(){}
registerHelper_(){
getInitMap()[std::string(ClassName)]=&TParent::factory_init_;
}
};
template<class TParent, const char* ClassName>
registerHelper_<TParent,ClassName> registerHelper_<TParent,ClassName>::help_;
}
class Factory : detail_::registerHelperBase
{
private:
Factory();
public:
static void* createObject(const std::string& objclassname) {
return getInitMap().at(objclassname)();
}
};
template <class TClass, const char* ClassName>
class FactoryBase {
private:
static detail_::registerHelper_<FactoryBase<TClass,ClassName>,ClassName> factory_helper_;
static void* factory_init_(){ return new TClass();}
public:
friend class detail_::registerHelper_<FactoryBase<TClass,ClassName>,ClassName>;
FactoryBase(){
//factory_helper_.doNothing();
}
virtual ~FactoryBase(){};
};
template <class TClass, const char* ClassName>
detail_::registerHelper_<FactoryBase<TClass,ClassName>,ClassName> FactoryBase<TClass,ClassName>::factory_helper_;
FACTORY_CLASS(Test) {
public:
Test(){}
};
int main(int argc, char** argv) {
try {
Test* test = (Test*) Factory::createObject("Test");
}
catch(const std::exception& ex) {
std::cerr << "caught std::exception: "<< ex.what() << std::endl;
}
#ifdef _MSC_VER
system("pause");
#endif
return 0;
}
The problem is not related to initialization order, but rather to template instantiation.
Templated code is instantiated on demand, that is, the compiler will not instantiate any templated code that is not used in your program. In particular, in your case the static class member FactoryBase<>::factory_helper_ is not being instantiated and thus it does not exist in the final binary, it does not register itself... (you can check this with 'nm' from the gnu toolchain, that will show the list of symbols present in your executable)
Try changing the FactoryBase constructor to this:
template <class TClass, const char* ClassName>
class FactoryBase {
//...
FactoryBase(){
factory_helper_;
}
//...
};
This will force the compiler into actually instantiating the static member in the binary and you should be set. There is no need to create an empty method and calling it.
EDIT: As an answer to the comment, towards the end of paragraph ยง14.7.1[temp.inst]/1 in the current standard:
Unless a member of a class template or
a member template has been explicitly
instantiated or explicitly
specialized, the specialization of the
member is implicitly instantiated when
the specialization is referenced in a
context that requires the member
definition to exist; in particular,
the initialization (and any associated
side-effects) of a static data member
does not occur unless the static data
member is itself used in a way that
requires the definition of the static
data member to exist.
#define FACTORY_CLASS(classtype) \
class classtype; \
extern const char classtype##_name_[] = #classtype; \
template detail_::registerHelper_<FactoryBase<classtype,classtype##_name_>,classtype##_name_> FactoryBase<classtype,classtype##_name_>::factory_helper_; \
class classtype : FactoryBase<classtype,classtype##_name_>
explicitly instantiating factory_helper_ fixed the issue.