B
Brian Riis
This all pertains to the above mentioned article. Anyone want to read it
(it's rather neat, actually), here's the address:
http://www.cuj.com/documents/s=8205/cujweb0305meynard/
Anyway, I was trying to work my way through the idea of the class,
especially the one, that uses a template parameter for the enumeration
value, in the hopes of getting an enum that enumerated through std::strings.
The whole idea is to keep a base class with a static std::set<> of
pointers to static instantiations of a derived class. The whole shebang
designed using the Curiously Recurring Template Pattern (meaning that
the derived class passes itself as a template parameter to the base
class). Here's a simplified implementation (read the above link for full
details.
<code>
template <class T, class TValue>
class Enum
{
private:
// Actually needs a "less-than" predicate. Omitted here...
static std::set<Enum<T, TValue> *> s_instances;
TValue m_value;
protected:
explicit Enum(TValue const & value): m_value(value)
{
s_instances.insert(this);
}
public:
TValue const & get_value() const { return m_value; }
// ... more static functions follow to implement an STL-like
// interface to the enum; begin(), end(), size(), et al.
};
// instantiate the s_instances std::set<>
template <class T, class TValue>
typename std::set<Enum<T, TValue> *>
Enum<T, TValue>::s_instances;
// An actual "enum", enumerated on std::string
class Enum_String
: Enum<Enum_String, std::string> // <- Curiously Recurring Template
{
private:
explicit Enum_String(std::string const & value)
: Enum<Enum_String, std::string>(value){} // Base class "inserts"
public:
static const Enum_String Alpha;
static const Enum_String Beta;
// ... however many _valid_ values of Enum_String is needed...
};
// Instantiate the static "Enum_String"s
const Enum_String Enum_String::Alpha("Alpha");
const Enum_String Enum_String::Beta ("Beta");
</code>
Here's the problem. At the above instantiations, an anonymous
std::string ("Alpha") is constructed and passed to Enum_String's
constructor. (Pseudo-code)
Enum_String::Enum_String(std::string("Alpha"))
This constructor, in turn, passes the value to the instantiated base
class' constructor.
Enum<Enum_String, std::string>::Enum(std::string("Alpha"))
This constructor set the m_value member variable *and inserts a pointer
to this into the set*!!! Or at least it tries to.
Problem is, AFAIK, C++ does not guarantee that the s_instances variable
has been constructed at this time. Both s_instances and the
"Enum_String"s are constructed globally, but I believe that there is no
guarantee that s_instances is constructed first, making the construction
of Enum_String impossible (since the constructor relies on s_instances).
If I understand C++ rules correctly, this may work or not, as "the wind
blows", depending on whether the compiler decides to instantiate
s_instances first or not.
Now my question is: Is there a way to get around this problem, ie. make
sure that s_instances is constructed *before* any of the Enum_String
instances?
Or have I misunderstood completely? (always a possibility! )
Opinions and comments, please!
(it's rather neat, actually), here's the address:
http://www.cuj.com/documents/s=8205/cujweb0305meynard/
Anyway, I was trying to work my way through the idea of the class,
especially the one, that uses a template parameter for the enumeration
value, in the hopes of getting an enum that enumerated through std::strings.
The whole idea is to keep a base class with a static std::set<> of
pointers to static instantiations of a derived class. The whole shebang
designed using the Curiously Recurring Template Pattern (meaning that
the derived class passes itself as a template parameter to the base
class). Here's a simplified implementation (read the above link for full
details.
<code>
template <class T, class TValue>
class Enum
{
private:
// Actually needs a "less-than" predicate. Omitted here...
static std::set<Enum<T, TValue> *> s_instances;
TValue m_value;
protected:
explicit Enum(TValue const & value): m_value(value)
{
s_instances.insert(this);
}
public:
TValue const & get_value() const { return m_value; }
// ... more static functions follow to implement an STL-like
// interface to the enum; begin(), end(), size(), et al.
};
// instantiate the s_instances std::set<>
template <class T, class TValue>
typename std::set<Enum<T, TValue> *>
Enum<T, TValue>::s_instances;
// An actual "enum", enumerated on std::string
class Enum_String
: Enum<Enum_String, std::string> // <- Curiously Recurring Template
{
private:
explicit Enum_String(std::string const & value)
: Enum<Enum_String, std::string>(value){} // Base class "inserts"
public:
static const Enum_String Alpha;
static const Enum_String Beta;
// ... however many _valid_ values of Enum_String is needed...
};
// Instantiate the static "Enum_String"s
const Enum_String Enum_String::Alpha("Alpha");
const Enum_String Enum_String::Beta ("Beta");
</code>
Here's the problem. At the above instantiations, an anonymous
std::string ("Alpha") is constructed and passed to Enum_String's
constructor. (Pseudo-code)
Enum_String::Enum_String(std::string("Alpha"))
This constructor, in turn, passes the value to the instantiated base
class' constructor.
Enum<Enum_String, std::string>::Enum(std::string("Alpha"))
This constructor set the m_value member variable *and inserts a pointer
to this into the set*!!! Or at least it tries to.
Problem is, AFAIK, C++ does not guarantee that the s_instances variable
has been constructed at this time. Both s_instances and the
"Enum_String"s are constructed globally, but I believe that there is no
guarantee that s_instances is constructed first, making the construction
of Enum_String impossible (since the constructor relies on s_instances).
If I understand C++ rules correctly, this may work or not, as "the wind
blows", depending on whether the compiler decides to instantiate
s_instances first or not.
Now my question is: Is there a way to get around this problem, ie. make
sure that s_instances is constructed *before* any of the Enum_String
instances?
Or have I misunderstood completely? (always a possibility! )
Opinions and comments, please!