My example class has a static array of characters, and I want to create a map from the characters to the indices. I need to initialize this static map in a for loop in my "example.cpp" file. However, C "expects a declaration". Is there any way of populating my map as a declaration? In general, is it possible to create a constructor for the static variables that handles all this initialization before the constructor for the class variables is called?
Here is my example class.
#include <map>
using namespace std;
class Example {
static char chars[4];
static map<char,int> char2idx;
};
char Example::chars[4] = {'a','b','c','d'};
for(int i=0; i<4;i ) {
Example::char2idx[Example::chars[i]] = i;
}
I am getting the following error when I try to compile.
clang -std=c 11 -Wall -g -c -o example.o example.cpp
example.cpp:9:1: error: expected unqualified-id
for(int i=0; i<4;i ) {
^
1 error generated.
CodePudding user response:
Quick fix: Make a helper function
#include <map>
using namespace std;
class Example {
friend map<char,int> helper(); // so it can see the private members
static char chars[4];
static map<char,int> char2idx;
};
map<char,int> helper() // does the work, returns the map
{
map<char,int> out;
// for(int i=0; i<4;i ) { that four is ugly. What if chars changes in size?
for(int i=0; i<std::size(Example::chars);i ) { // if we didn't want i I'd use
// a range-based for to make
// life even simpler.
out[Example::chars[i]] = i;
}
return out; // return by value. copy elision is your friend!
}
char Example::chars[4] = {'a','b','c','d'};
map<char,int> Example::char2idx = helper();
CodePudding user response:
The ur-example in C is how std::cin
, std::cout
, etc are initialized. The core trick is to have a local static variable in the global namespace that calls the static constructor:
example.hpp
class Example
{
static stuff here;
static bool initialize();
};
static bool b_initialize_Example = Example::initialize();
example.cpp
bool Example::initialize()
{
static bool is_initialized = false;
if (!is_initialized)
{
// do your for loop here.
}
return is_initialized = true;
}
Anther way is to use a factory to generate instances of your class. The first time you generate an instance, initialize the static data.
// No example here. Google around factory methods.
// You’ll still need a static bool is_initialized somewhere.
Finally, you can just use a static initializer in your class’s constructor. This is similar to the first method:
class Example
{
Example() { initialize(); ... }
static void initialize()
{
static bool is_initialized = false;
if (is_initialized) return;
// initialize stuff here
is_initialized = true;
}
};
I’m sure there are other ways to go about this, but that’s what is on the top of my head.
EDIT: the example in the other answer is nice too!