Reputation: 872
I have a template class intended to help with enum string conversion. It's based on this solution to automatically initializing static variables. The full class is as follows:
template <typename LabelType>
class EnumHelper
{
public:
static const char* ToString(LabelType label)
{
return enumBimap_.left.at(label);
}
static LabelType ToEnum(const char* name)
{
return enumBimap_.right.at(name);
}
static bool IsInitialized() { return initialized_; }
private:
typedef boost::bimap<LabelType, const char*> EnumBimap;
EnumHelper() = delete;
EnumHelper(const EnumHelper&) = delete;
static void Init(int numLabels, const char* names[])
{
for (int i = 0; i < numLabels; i++)
{
enumBimap_.insert(EnumBimap::value_type((LabelType)i, names[i]));
}
initialized_ = true;
}
class Initializer
{
public:
Initializer();
};
static EnumBimap enumBimap_;
static bool initialized_;
static Initializer initializer_;
friend class Initializer;
};
template <typename LabelType>
typename EnumHelper<LabelType>::EnumBimap EnumHelper<LabelType>::enumBimap_;
template <typename LabelType>
bool EnumHelper<LabelType>::initialized_ = false;
template <typename LabelType>
typename EnumHelper<LabelType>::Initializer EnumHelper<LabelType>::initializer_;
The macro for initializing it specializes the Init method for the particular enum, and instantiates the template for that enum:
#define INIT_ENUM_HELPER(labelType, labelNames, count) \
template <> \
EnumHelper<labelType>::Initializer::Initializer() \
{ \
EnumHelper<labelType>::Init(count, labelNames); \
} \
template class EnumHelper<labelType>;
Now I'm using this successfully in two cases in a library statically linked to my application, but in another case the Init never gets called. The initialization is exactly the same (calling the macro in a .cpp in the library) I've run through a couple of possibilities for it not working, including that it doesn't get referenced in the library itself, and that the enum was initially internal to a class (grasping at straws) but I really am at a bit of a loss now.
Under what conditions would that static Initalizer object not be constructed, hence not calling the Init?
Upvotes: 0
Views: 69
Reputation: 872
Not an answer to getting this data to initialize automatically across libraries, but an alternative implementation that doesn't rely on automatic static initialization and is lazy initialized as needed:
// Helper for easily obtaining string representations of enum values and vice versa
template <typename LabelType>
class EnumHelper
{
public:
typedef boost::bimap<LabelType, std::string > EnumBimap;
static const char* ToString(LabelType label)
{
auto const& left = Instance().enumBimap_.left;
auto iter = left.find(label);
if (iter != left.end())
{
return iter->second.c_str();
}
else
{
return "UNDEFINED_ENUM_VALUE";
}
}
static LabelType ToEnum(const char* name)
{
auto const& right = Instance().enumBimap_.right;
std::string str(name);
auto iter = right.find(str);
CHECK_THROW(iter != right.end(), ERROR_MISSING_VALUE, "ENUM");
return iter->second;
}
static bool IsInitialized() { return true; }
private:
EnumHelper() = delete;
EnumHelper(const EnumHelper&) = delete;
EnumHelper(int numLabels, const char* names[])
{
for (int i = 0; i < numLabels; i++)
{
std::string str(names[i]);
enumBimap_.insert(EnumBimap::value_type((LabelType)i, str));
}
}
static const EnumHelper& Instance();
EnumBimap enumBimap_;
};
// Sets up a specific enum helper by having its instance accessor init with appropriate label names
#define INIT_ENUM_HELPER(labelType, labelNames, count) \
template <> \
const EnumHelper<labelType>& EnumHelper<labelType>::Instance() \
{ \
static EnumHelper<labelType> enumHelper(count, labelNames); \
return enumHelper; \
}
This is easily set up for a particular enum:
// In .h
enum class GameStateLabels
{
LOADING,
INTRO,
PLAY,
RESULTS,
COUNT
};
const char* GAME_STATE_LABEL_NAMES[];
// In .cpp
const char* VSE::GAME_STATE_LABEL_NAMES[] =
{
"LOADING",
"INTRO",
"PLAY",
"RESULTS"
};
INIT_ENUM_HELPER(GameStateLabels, GAME_STATE_LABEL_NAMES, (int)GameStateLabels::COUNT)
If anyone has an actual solution for the original issue, I'm happy to try it and accept it if it works :)
Upvotes: 0