How to Force a Static Member to Be Initialized

How to force a static member to be initialized?

Consider:

template<typename T, T> struct value { };

template<typename T>
struct HasStatics {
static int a; // we force this to be initialized
typedef value<int&, a> value_user;
};

template<typename T>
int HasStatics<T>::a = /* whatever side-effect you want */ 0;

It's also possible without introducing any member:

template<typename T, T> struct var { enum { value }; };
typedef char user;

template<typename T>
struct HasStatics {
static int a; // we force this to be initialized
static int b; // and this

// hope you like the syntax!
user :var<int&, a>::value,
:var<int&, b>::value;
};

template<typename T>
int HasStatics<T>::a = /* whatever side-effect you want */ 0;

template<typename T>
int HasStatics<T>::b = /* whatever side-effect you want */ 0;

trying to force static object initialization

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

Is there a way to force static fields to be initialized in C#?

The answer to your question is 'well, yes'. But one of the two ways of "forcing" it is what you're already doing.

The relevant section in the language spec is Static constructors, and specifically:

The static constructor for a class executes at most once in a given
application domain. The execution of a static constructor is triggered
by the first of the following events to occur within an application
domain:

  • An instance of the class is created.
  • Any of the static members of the class are referenced.

If a class contains the Main method (Section 3.1) in which execution
begins, the static constructor for that class executes before the Main
method is called. If a class contains any static fields with
initializers, those initializers are executed in textual order
immediately prior to executing the static constructor.

How to initialize private static members in C++?

The class declaration should be in the header file (Or in the source file if not shared).

File: foo.h

class foo
{
private:
static int i;
};

But the initialization should be in source file.

File: foo.cpp

int foo::i = 0;

If the initialization is in the header file then each file that includes the header file will have a definition of the static member. Thus during the link phase you will get linker errors as the code to initialize the variable will be defined in multiple source files.
The initialisation of the static int i must be done outside of any function.

Note: Matt Curtis: points out that C++ allows the simplification of the above if the static member variable is of const integer type (bool, char, char8_t [since C++20], char16_t, char32_t, wchar_t, short, int, long, long long, or any implementation-defined extended integer types, including any signed, unsigned, and cv-qualified variants.). You can then declare and initialize the member variable directly inside the class declaration in the header file:

class foo
{
private:
static int const i = 42;
};

Why static members need to be initialized out of the class

What you call initialization is really a definition.

And the reason is that definitions can only be done once is a single translation unit.

If the static member variable were defined in the header file it could be defined multiple times breaking the one definition rule.

Or the compiler would not know which translation unit to put the definition in, since it doesn't know anything about other possible translation units.

Pure virtual variable OR: how to force derived class to init a static member variable?

As I understand it, you are trying to express the following invariant:

Any class derived from Light is known to have a const static member Colors of type Color[].

Now you're essentially correct that virtual associates stuff to the runtime type of an object, and if you were able to have this "stuff" include not only methods but arbitrary data then you'd be able to store this Colors member inside the vtable of each class derived from Light.

If this is the sort of approach you want to take, then it implies that any time you want to access Colors you have on hand an instance of a derived class. If that's your use case, then you can just use a virtual method, like so:

class Light
{
public:

virtual std::vector<Color> & getColors() = 0;
};

class NormalLight : public Light
{
private:

static std::vector<Color> _colors;

public:

std::vector<Color> & getColors() final
{
return _colors;
}
}

However, this is more limited that what you'd get from a true static member.

If there really is only ever going to be one instance of any class derived from Light, you could instead have Light own a static member that its derived classes inherit, and which they initialize from their constructors. Then when the constructor for whatever kind of light you have is called, the static member will be initialized.

class Light
{
public:

static Light * instance;

static std::vector<Color> Colors;

Light * getInstance()
{
assert(instance != nullptr);
return instance;
}

void createInstance(const std::string & type);

};

class NormalLight : public Light
{
public:

NormalLight()
{
Colors = { RED, GREEN, BLUE };
}
};

class SpecialLight : public Light
{
public:

SpecialLight()
{
Colors = { MAROON, MINT, MIDNIGHT };
}
};

// ...

static Light * Light::instance = nullptr;

static std::vector<Color> Light::Colors;

void Light::createInstance(const std::string & type)
{
assert(instance == nullptr);

if(type == "Normal")
{
Light::instance = new NormalLight();
}
else
{
Light::instance = new SpecialLight();
}
}

This is missing Light::Colors being const, but that seems inherently necessary if we only determine its value at runtime after determining whether whether we are a normal or a special light.

A final approach would be to use templates. This gets us closer to the idea of "any type of this form has a member called such-and-such."

In particular, you can just give both NormalLight and SpecialLight their own const static members called Color, and then use the magic of templates to access the member with that name. Here's an example:

struct ILight
{
void setColor(Color);
};

template<class T>
class Light : public ILight
{
private:

Color myColor;

public:

void setColor(Color newColor)
{
for(Color color : T::Colors)
{
if(color == newColor)
{
myColor = newColor;
return;
}
}

throw std::runtime_error("Color not allowed");
}

Color getColor() { return myColor; }
};


struct NormalLight : public Light<NormalLight>
{
const static Color Colors[];
};


struct SpecialLight : public Light<NormalLight>
{
const static Color Colors[];
};

// ...

const Color NormalLight::Colors[] = { RED, GREEN, BLUE };
const Color SpecialLight::Colors[] = { MAROON, MINT, MIDNIGHT };

I'm honestly not sure I recommend any of these approaches; in fact, I don't really recommend the use of singletons at all. That said, I hope this clears up some of the issues involved and helps you make your own decisions about the tradeoffs.

Initializing static class members in an initialize function


What does the mean for the static members before the Initialize function is called (I do intend on putting an initialized bool in there as well)?

You're creating a local variable called _val (this should be _value?), which has nothing to do with your static variable. As such, your code won't even link.


To do what you're intending, you would initialise the variable, just like you've shown in your first Example.cpp, but without any constructor arguments:

#include "Example.h"
OtherClass Example::_value;

Make sure that the no-argument constructor doesn't perform any actual initialisation! We're going to delay this by making an OtherClass::initialize method.

#include "Example.h"
OtherClass Example::_value;

Example::Initialize()
{
Example::_value.initialize(...);
}

Alternatively, you could make _value a pointer, assign it to NULL and allocate it on the heap when you need it:

#include "Example.h"
OtherClass *Example::_value = NULL;

Example::Initialize()
{
Example::_value = new OtherClass(...);
}

Don't forget to delete it when you don't need it anymore. Or, if you can use C++11, use an std::shared_ptr<OtherClass> instead.

Call a method of a static member for initialization in C++

if BoostLogger doesn't provide the constructor to add_attribute you may create your own function for that, something like:

class MyClass
{
private:
static BoostLogger m_logger;
};

BoostLogger CreateBoostLoggerWithClassName(const std::string& className)
{
BoostLogger logger;
logger.add_attribute(
"ClassName",
boost::log::attributes::constant<std::string>(className));
return logger;
}

BoostLogger MyClass::m_logger = CreateBoostLoggerWithClassName("MyClass");


Related Topics



Leave a reply



Submit