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.
Related
I am wondering if it is possible to do:
class MyClass
{
public:
MyClass();
...
#if defined USE_TYPE_ONE
static TypeOne myVariable;
#else
static TypeTwo myVariable;
#endif USE_TYPE_ONE
};
The reason is that I have two classes, TypeOne & TypeTwo, with same function variables but different implementations and
I don't want to use macro in every place that myVariable is called.
EDIT
Thanks for prompt comments and answer. I have to mention that MyClass has been used a lot with different classes. That is why I would like to avoid template. Because even using template class with default template argument type, I have to use <> (change many other places) for other places that I use MyClass without need of TypeOne.
You can use a template as suggested but if you just need to switch between two types according to a condition and you have access to C++11 <type_traits> (otherwise consider updating your compiler), then you could use std::conditional:
#include <type_traits>
constexpr bool USE_TYPE_ONE = true;
struct TypeOne { };
struct TypeTwo { };
class MyClass {
using Type = std::conditional<USE_TYPE_ONE, TypeOne, TypeTwo>::type;
static Type myVariable;
};
As pointed out in the comments, you don't have to use macro's, you can use a templated class to achieve this:
template <typename T>
class MyClass
{
public:
MyClass();
static T myVariable;
};
Then instantiate it how you like (for example for int types):
MyClass<int>::myVariable;
Why wouldn't it be possible? It's totally possible. Of course you need to pass that preproc variable in the build somehow, and it'll be defined as that type for all code in the program...but it is indeed totally possible.
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 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!
I can't seem to init an static member inside an fully specialized class template!
I'm trying to do the following:
template<typename Type>
class X
{
};
template<>
class X<int>
{
public:
static int Value;
}
But i can't seem to init the static member, i tried everything like:
template<>
int X<int>::Value = 0;
It doesn't compile, so any pointers on how to actually do this would be nice ;)
Edit: the answer beneath is correct but you also need to place the init in the .cpp file and not in the header file.
Thanks for your time,
Richard.
Don't use template<> while defining Value because template<> is not allowed in member definition of explicitly specialized class[X<int> in this case]. Moreover you are missing a semicolon after }
This works for me:
template<typename Type>
class X
{
};
template<>
class X<int>
{
public:
static int Value;
};
int X<int>::Value = 0;