Compile time Meta-programming, with string literals - c++

I'm writing some code which could really do with some simple compile time metaprogramming. It is common practise to use empty-struct tags as compile time symbols. I need to decorate the tags with some run-time config elements. static variables seem the only way to go (to enable meta-programming), however static variables require global declarations. to side step this Scott Myers suggestion (from the third edition of Effective C++), about sequencing the initialization of static variables by declaring them inside a function instead of as class variables, came to mind.
So I came up with the following code, my hypothesis is that it will let me have a compile-time symbol with string literals use-able at runtime. I'm not missing anything I hope, and that this will work correctly, as long as I populate the runtime fields before I Initialize the depending templates classes ? .
#include <string>
template<class Instance>
class TheBestThing {
public:
static void set_name(const char * name_in) {
get_name() = std::string(name_in);
}
static void set_fs_location(const char * fs_location_in) {
get_fs_location() = std::string(fs_location_in);
}
static std::string & get_fs_location() {
static std::string fs_location;
return fs_location;
}
static std::string & get_name() {
static std::string name;
return name;
}
};
struct tag {};
typedef TheBestThing<tag> tbt;
int main()
{
tbt::set_name("xyz");
tbt::set_fs_location("/etc/lala");
ImportantObject<tbt> SinceSlicedBread;
}
edit:
Made community wiki.

I've finally understood what the problem was... and your solution does not solve much, if any.
The goal of using local static variable is to provide initialization on first use, thus being safe from the "Initialization Order Fiasco" (by the way, it does not solve the "Destruction Order Fiasco").
But with your design, if you effectively prevent the crash you do not however prevent the issue of using a variable before its value is used.
ImportantObject<tbt> SinceSliceBread; // using an empty string
tbt::set_name("xyz");
Compare with the following use:
std::string& tbt::get_name() { static std::string MName = "xyz"; return MName; }
Here the name is not only created but also initialized on first use. What's the point of using a non initialized name ?
Well, now that we know your solution does not work, let's think a bit. In fact we would like to automate this:
struct tag
{
static const std::string& get_name();
static const std::string& get_fs_location();
};
(with possibly some accessors to modify them)
My first (and easy) solution would be to use a macro (bouh not typesafe):
#define DEFINE_NEW_TAG(Tag_, Name_, FsLocation_) \
struct Tag_ \
{ \
static const std::string& get_name() { \
static const std::string name = #Name_; \
return name; \
} \
static const std::string& get_fs_location() { \
static const std::string fs_location = #FsLocation_; \
return fs_location; \
} \
};
The other solution, in your case, could be to use boost::optional to detect that the value has not been initialized yet, and postpone initialization of the values that depend on it.

Related

Constructor body execution for a const global object?

So I was trying to set up an easy way for future developments to define log-messages.
I thought of the following object-initialization inside a Header (as a global variable "SYSTEM_START"; not inside a function!):
const LogMessage SYSTEM_STARTED(0x0001, DEBUG, "System started");
which needs other declarations from a different header (just for the example here):
enum LogSeverity_E : uint8_t
{
INFO = 0x01,
DEBUG = 0x02
};
class LogMessage
{
public:
LogMessage( uint16_t messageId, LogSeverity_E severityId, const char* text = nullptr );
const char* getText() const;
private:
uint16_t messageId_;
LogSeverity_E severityId_;
const char* text_;
};
and its definition in a cpp:
LogMessage::LogMessage(uint16_t messageId, LogSeverity_E severityId, ConstCharPtr text) :
messageId_ { messageId }, severityId_ {severityId}, text_ { text }
{
/* if I call a function here, e.g. a Singleton-function-call. What will happen if the object is initialized as a local/global variable like at the top? */
};
const char* LogMessage::getText() const
{
return text_;
};
I am not working on a PC but on an embedded hardware with a special compiler. And what I saw here is that it calls this constructor even before jumping to main and so it also calls a singleton there as well.
I couldn't find any definition for this behaviour inside the cppreference nor elsewhere because everywhere the constructor-body for constant objects is just empty.
so as the comment in the constructor states: what happens if I call a function there in this specific example with const-objects as global variables? Is my explained behaviour that happens here a legal behaviour? Is even the usage of this code like this a legal behaviour? Or am I just lucky with my compiler and my embedded hw?

Searchable Enum-like object with string and int conversion

Intro
The enum type in C++ is fairly basic; it basically just creates a bunch of compile-time values for labels (potentially with proper scoping with enum class).
It's very attractive for grouping related compile-time constants together:
enum class Animal{
DOG,
CAT,
COW,
...
};
// ...
Animal myAnimal = Animal::DOG;
However it has a variety of perceived shortcomings, including:
No standard way to get the number of possible elements
No iteration over elements
No easy association of enum with string
In this post, I seek to create a type that addresses those perceived shortcomings.
An ideal solution takes the notion of compile-time knowledge of constants and their associations with strings and groups them together into an scoped-enum-like object that is searchable both by enum id and enum string name. Finally, the resulting type would use syntax that is as close to enum syntax as possible.
In this post I'll first outline what others have attempted for the individual pieces, and then walk through two approaches, one that accomplishes the above but has undefined behavior due to order of initialization of static members, and another solution that has less-pretty syntax but no undefined behavior due to order of initialization.
Prior work
There are plenty of questions on SO about getting the number of items in an enum (1 2 3) and plenty of other questions on the web asking the same thing (4 5 6) etc. And the general consensus is that there's no sure-fire way to do it.
The N'th element trick
The following pattern only works if you enforce that enum values are positive and increasing:
enum Foo{A=0, B, C, D, FOOCOUNT}; // FOOCOUNT is 4
But is easily broken if you're trying to encode some sort of business logic that requires arbitrary values:
enum Foo{A=-1, B=120, C=42, D=6, FOOCOUNT}; // ????
Boost Enum
And so the developers at Boost attempted to solve the issue with Boost.Enum which uses some fairly complicated macros to expand into some code that will at least give you the size.
Iterable Enums
There have been a few attempts at iterable enums; enum-like objects that one can iterate over, theoretically allowing for implicit size computation, or even explicitly in the case of [7] (7 8 9, ...)
Enum to String conversion
Attempts to implement this usually result in free-floating functions and the use of macros to call them appropriately. (8 9 10)
This also covers searching enums by string (13)
Additional Constraints
No macros
Yes, this means no Boost.Enum or similar approach
Need int->Enum and Enum-int Conversion
A rather unique problem when you start moving away from actual enums;
Need to be able to find enum by int (or string)
Also a problem one runs into when they move away from actual enums. The list of enums is considered a collection, and the user wants to interrogate it for specific, known-at-compile-time values. (See iterable enums and Enum to String conversion)
At this point it becomes pretty clear that we cannot really use an enum anymore. However, I'd still like an enum-like interface for the user
Approach
Let's say I think that I'm super clever and realize that if I have some class A:
struct A
{
static int myInt;
};
int A::myInt;
Then I can access myInt by saying A::myInt.
Which is the same way I'd access an enum:
enum A{myInt};
// ...
// A::myInt
I say to myself: well I know all my enum values ahead of time, so an enum is basically like this:
struct MyEnum
{
static const int A;
static const int B;
// ...
};
const int MyEnum::A = 0;
const int MyEnum::B = 1;
// ...
Next, I want to get fancier; let's address the constraint where we need std::string and int conversions:
struct EnumValue
{
EnumValue(std::string _name): name(std::move(_name)), id(gid){++gid;}
std::string name;
int id;
operator std::string() const
{
return name;
}
operator int() const
{
return id;
}
private:
static int gid;
};
int EnumValue::gid = 0;
And then I can declare some containing class with static EnumValues:
MyEnum v1
class MyEnum
{
public:
static const EnumValue Alpha;
static const EnumValue Beta;
static const EnumValue Gamma;
};
const EnumValue MyEnum::Alpha = EnumValue("Alpha")
const EnumValue MyEnum::Beta = EnumValue("Beta")
const EnumValue MyEnum::Gamma = EnumValue("Gamma")
Great! That solves some of our constraints, but how about searching the collection? Hm, well if we now add a static container like unordered_map, then things get even cooler! Throw in some #defines to alleviate string typos, too:
MyEnum v2
#define ALPHA "Alpha"
#define BETA "Beta"
#define GAMMA "Gamma"
// ...
class MyEnum
{
public:
static const EnumValue& Alpha;
static const EnumValue& Beta;
static const EnumValue& Gamma;
static const EnumValue& StringToEnumeration(std::string _in)
{
return enumerations.find(_in)->second;
}
static const EnumValue& IDToEnumeration(int _id)
{
auto iter = std::find_if(enumerations.cbegin(), enumerations.cend(),
[_id](const map_value_type& vt)
{
return vt.second.id == _id;
});
return iter->second;
}
static const size_t size()
{
return enumerations.size();
}
private:
typedef std::unordered_map<std::string, EnumValue> map_type ;
typedef map_type::value_type map_value_type ;
static const map_type enumerations;
};
const std::unordered_map<std::string, EnumValue> MyEnum::enumerations =
{
{ALPHA, EnumValue(ALPHA)},
{BETA, EnumValue(BETA)},
{GAMMA, EnumValue(GAMMA)}
};
const EnumValue& MyEnum::Alpha = enumerations.find(ALPHA)->second;
const EnumValue& MyEnum::Beta = enumerations.find(BETA)->second;
const EnumValue& MyEnum::Gamma = enumerations.find(GAMMA)->second;
Full working demo HERE!
Now I get the added benefit of searching the container of enums by name or id:
std::cout << MyEnum::StringToEnumeration(ALPHA).id << std::endl; //should give 0
std::cout << MyEnum::IDToEnumeration(0).name << std::endl; //should give "Alpha"
BUT
This all feels very wrong. We're initializing a LOT of static data. I mean, it wasn't until recently that we could populate a map at compile time! (11)
Then there's the issue of the static-initialization order fiasco:
A subtle way to crash your program.
The static initialization order fiasco is a very subtle and commonly
misunderstood aspect of C++. Unfortunately it’s very hard to detect —
the errors often occur before main() begins.
In short, suppose you have two static objects x and y which exist in
separate source files, say x.cpp and y.cpp. Suppose further that the
initialization for the y object (typically the y object’s constructor)
calls some method on the x object.
That’s it. It’s that simple.
The tragedy is that you have a 50%-50% chance of dying. If the
compilation unit for x.cpp happens to get initialized first, all is
well. But if the compilation unit for y.cpp get initialized first,
then y’s initialization will get run before x’s initialization, and
you’re toast. E.g., y’s constructor could call a method on the x
object, yet the x object hasn’t yet been constructed.
I hear they’re hiring down at McDonalds. Enjoy your new job flipping
burgers.
If you think it’s “exciting” to play Russian Roulette with live rounds
in half the chambers, you can stop reading here. On the other hand if
you like to improve your chances of survival by preventing disasters
in a systematic way, you probably want to read the next FAQ.
Note: The static initialization order fiasco can also, in some cases,
apply to built-in/intrinsic types.
Which can be mediated with a getter function that initializes your static data and returns it (12):
Fred& GetFred()
{
static Fred* ans = new Fred();
return *ans;
}
But if I do that, now I have to call a function to initialize my static data, and I lose the pretty syntax you see above!
#Questions#
So, now I finally get around to my questions:
Be honest, how bad is the above approach? In terms of initialization order safety and maintainability?
What kind of alternatives do I have that are still pretty for the end user?
EDIT
The comments on this post seem to indicate a strong preference for static accessor functions to get around the static order initialization problem:
public:
typedef std::unordered_map<std::string, EnumValue> map_type ;
typedef map_type::value_type map_value_type ;
static const map_type& Enumerations()
{
static map_type enumerations {
{ALPHA, EnumValue(ALPHA)},
{BETA, EnumValue(BETA)},
{GAMMA, EnumValue(GAMMA)}
};
return enumerations;
}
static const EnumValue& Alpha()
{
return Enumerations().find(ALPHA)->second;
}
static const EnumValue& Beta()
{
return Enumerations().find(BETA)->second;
}
static const EnumValue& Gamma()
{
return Enumerations().find(GAMMA)->second;
}
Full working demo v2 HERE
Questions
My Updated questions are as follows:
Is there another way around the static order initialization problem?
Is there a way to perhaps only use the accessor function to initialize the unordered_map, but still (safely) be able to access the "enum" values with enum-like syntax? e.g.:
MyEnum::Enumerations()::Alpha
or
MyEnum::Alpha
Instead of what I currently have:
MyEnum::Alpha()
Regarding the bounty:
I believe an answer to this question will also solve the issues surrounding enums I've elaborated in the post (Enum is in quotes because the resulting type will not be an enum, but we want enum-like behavior):
getting the size of an "enum"
string to "enum" conversion
a searchable "enum".
Specifically, if we could do what I've already done, but somehow accomplish syntax that is enum-like while enforcing static initialization order, I think that would be acceptable
Sometimes when you want to do something that isn't supported by the language, you should look external to the language to support it. In this case, code-generation seems like the best option.
Start with a file with your enumeration. I'll pick XML completely arbitrarily, but really any reasonable format is fine:
<enum name="MyEnum">
<item name="ALPHA" />
<item name="BETA" />
<item name="GAMMA" />
</enum>
It's easy enough to add whatever optional fields you need in there (do you need a value? Should the enum be unscoped? Have a specified type?).
Then you write a code generator in the language of your choice that turns that file into a C++ header (or header/source) file a la:
enum class MyEnum {
ALPHA,
BETA,
GAMMA,
};
std::string to_string(MyEnum e) {
switch (e) {
case MyEnum::ALPHA: return "ALPHA";
case MyEnum::BETA: return "BETA";
case MyEnum::GAMMA: return "GAMMA";
}
}
MyEnum to_enum(const std::string& s) {
static std::unordered_map<std::string, MyEnum> m{
{"ALPHA", MyEnum::ALPHA},
...
};
auto it = m.find(s);
if (it != m.end()) {
return it->second;
}
else {
/* up to you */
}
}
The advantage of the code generation approach is that it's easy to generate whatever arbitrary complex code you want for your enums. Basically just side-step all the problems you're currently having.
I usually prefer non-macro code but in this case, I don't see what's wrong with macros.
IMHO, for this task macros are a much better fit as they are simpler and shorter to write and to read, and the same goes for the generated code. Simplicity is a goal in its own right.
These 2 macro calls:
#define Animal_Members(LAMBDA) \
LAMBDA(DOG) \
LAMBDA(CAT) \
LAMBDA(COW) \
CREATE_ENUM(Animal,None);
Generate this:
struct Animal {
enum Id {
None,
DOG,
CAT,
COW
};
static Id fromString( const char* s ) {
if( !s ) return None;
if( strcmp(s,"DOG")==0 ) return DOG;
if( strcmp(s,"CAT")==0 ) return CAT;
if( strcmp(s,"COW")==0 ) return COW;
return None;
}
static const char* toString( Id id ) {
switch( id ) {
case DOG: return "DOG";
case CAT: return "CAT";
case COW: return "COW";
default: return nullptr;
}
}
static size_t count() {
static Id all[] = { None, DOG, CAT, COW };
return sizeof(all) / sizeof(Id);
}
};
You could wrap them into a single macro using BOOST_PP and have a sequence for the members. This would make it a lot less readable, though.
You can easily change it to your preferences of default return values, or remove the default altogether, add a specific member value and string name, etc.
There's no loose functions, no init order hell, and only a bit of macro code that looks very much like the final result:
#define ENUM_MEMBER(MEMBER) \
, MEMBER
#define ENUM_FROM_STRING(MEMBER) \
if( strcmp(s,#MEMBER)==0 ) return MEMBER;
#define ENUM_TO_STRING(MEMBER) \
case MEMBER: return #MEMBER;
#define CREATE_ENUM_1(NAME,MACRO,DEFAULT) \
struct NAME { \
enum Id { \
DEFAULT \
MACRO(ENUM_MEMBER) \
}; \
static Id fromString( const char* s ) { \
if( !s ) return DEFAULT; \
MACRO(ENUM_FROM_STRING) \
return DEFAULT; \
} \
static const char* toString( Id id ) { \
switch( id ) { \
MACRO(ENUM_TO_STRING) \
default: return nullptr; \
} \
} \
static size_t count() { \
static Id all[] = { DEFAULT \
MACRO(ENUM_MEMBER) }; \
return sizeof(all) / sizeof(Id); \
} \
};
#define CREATE_ENUM_2(NAME,DEFAULT) \
CREATE_ENUM_1(NAME,NAME##_Members,DEFAULT)
#define CREATE_ENUM(NAME,DEFAULT) \
CREATE_ENUM_2(NAME,DEFAULT)
Hope this helps.

C++ : nameable objects belonging to an instance of a class, and stored in it

I am trying to make it possible for a programmer (who uses my library) to create nameable instances of type X that are stored inside an instance of class C (or at least are exclusive to that instance).
These are the only two (ugly) solutions I have managed to come up with (needless to say, I am just picking up C++)
1)
class C
{
public:
class XofC
{
public:
XofC() = delete;
XofC(C& mom)
{
mom.Xlist.emplace_front();
ref = Xlist.front();
}
X& access()
{
return ref;
}
private:
X& ref;
};
//etc
private:
std::forward_list<X> Xlist;
friend class XofC;
//etc
}
Problem:
Having to pass everywhere XofC instances.
2)
class C
{
public:
void newX(std::string);
X& getX(std::string);
//etc.
private:
/*possible run-time mapping implementation
std::vector<X> Xvec;
std::unordered_map<std::string, decltype(Xvec.size())> NameMap;
*/
//etc
}
Problem:
This does the job, but since all names of X (std::string) are known at compilation, the overhead of using run-time std::unordered_map<std::string, decltype(Xvec.size())> kind-of bugs me for something this simple.
Possible(?) solution: compile-time replacing of std::string with automatic index (int). Then I could use:
class C
{
public:
void newX(int); //int: unique index calculated at compile time from std::string
X& getX(int); //int: unique index calculated at compile time from std::string
//etc.
private:
std::vector<X> Xvec;
}
Questions:
Is there a 3)?
Is a compile time solution possible for 2)?
This is the real-life situation: I was starting my first C++ "project" and I thought I could use the practice and utility from an awesome user-friendly, simple and fast argument management library. I plan to make an ArgMan class which can parse the argV based on some specified switches. Switches would be named by the programmer descriptively and the trigger strings be specified (e.g. a switch named recurse could have "-r" and "-recursive" as triggers). When necessary, you should be easily able to get the setting of the switch. Implementation detail: ArgMan would have a std::unordered_map<std::string/*a trigger*/, ??/*something linking to the switch to set on*/>. This ensures an almost linear parse of argV relative to argC. How should I approach this?
You could 'abuse' non-type template arguments to get compiletime named instances:
Live on Coliru
Assume we have a data class X:
#include <string>
struct X
{
int has_some_properties;
std::string data;
};
Now, for our named instances, we define some name constants. The trick is, to give them external linkage, so we can use the address as a non-type template argument.
// define some character arrays **with external linkage**
namespace Names
{
extern const char Vanilla[] = "Vanilla";
extern const char Banana [] = "Banana";
extern const char Coconut[] = "Coconut";
extern const char Shoarma[] = "Shoarma";
}
Now, we make a NamedX wrapper that takes a const char* non-type template argument. The wrapper holds a static instance of X (the value).
// now we can "adorn" a `namedX` with the name constants (above)
template <const char* Name>
struct NamedX
{
static X value;
};
template <const char* Name> X NamedX<Name>::value;
Now you can use it like this:
int main()
{
X& vanilla = NamedX<Names::Vanilla>::value;
vanilla = { 42, "Woot!" };
return vanilla.has_some_properties;
}
Note that due to the fact that the template arguments are addresses, no actual string comparison is done. You cannot, e.g. use
X& vanilla = NamedX<"Vanilla">::value;
becuase "Vanilla" is a prvalue without external linkage. So, in fact you could do without some of the complexity and use tag structs instead: Live on Coliru
While Neil's solution did what I asked for, it was too gimmicky to use in my library. Also, sehe's trick is surely useful, but, if I understood correctly, but doesn't seem related to my question. I have decided to emulate the desired behavior using method 1), here is a less broken attempt at it:
class C
{
private:
class X
{
//std::string member;
//etc
};
public:
class XofC
{
public:
XofC(C & _mom) : mom(_mom)
{
mom.Xlist.emplace_front();
tehX = &(Xlist.front());
}
X & get(maybe)
{
if (&maybe != &mom) throw std::/*etc*/;
return &tehX;
}
private:
X * tehX;
C & mom;
};
private:
//etc
std::forward_list<X> Xlist;
friend class XofC;
//etc
};
Usage:
C foo;
bar = C::XofC(foo); //acts like an instance of X, but stored in C, but you have to use:
bar.get(foo)/*reference to the actual X*/.member = "_1_";
Of course, the downside is you have to make sure you pass bar everywhere you need it, but works decently.
This is how it looks like in my tiny argument manager library:
https://raw.github.com/vuplea/arg_manager.h/master/arg_manager.h

const correctness for configuration structures

I have a configuration file which gets read in, parsed and put into structures at the beginning of my programs run time.
The problem I am having is that I want these structures to be constant since the values in them should not change during the programs lifespan.
Currently I am doing the following:
config.h
#pragma warning(push)
#pragma warning(disable: 4510) /*-- we don't want a default constructor --*/
#pragma warning(disable: 4610) /*-- we don't want this to ever be user instantiated --*/
typedef struct SerialNode {
private:
void operator=(SerialNode&);
public:
const char* const port;
const char* const format;
} SerialNode;
#pragma warning(pop)
typedef std::map<const char*, const SerialNode*, MapStrComp> SerialMap;
SerialMap SerialConfig;
config.cpp
/*-- so we don't fall out of scope --*/
SerialNode* global_sn;
SerialNode local_sn = {port, format};
global_sn = new SerialNode(local_sn);
SerialConfig[key_store] = global_sn;
This works fine. However my problem is that now I am dealing with more complicated configuration data which requires me to pull a structure back out of the list, modify it and then put it back.
Obviously I can't modify it, so the solution would be something like:
SerialNode* global_sn;
SerialNode* old_sn = SerialConfig[key_store];
SerialNode local_sn = {port, format, old_sn->old_data, old_sn->more_old_data};
global_sn = new SerialNode(local_sn);
SerialConfig[key_store] = global_sn;
delete old_sn;
But this strikes me as bad programming practice. Is there is a better way to achieve what I'm going for which doesn't require such a hacked looking solution?
For reference, I'm using Visual Studio 2010
As always, the best thing you can do is not re-implement something that has already been written. There are a large number of libraries and frameworks that will help with serialization for c++:
Boost Serialization
Qt
Protocol Buffers
msgpack
Capn' Proto
Ideally the serialization framework you choose will exactly recreate the data graph that you are trying to store. Regardless of whether you have done any fixup, your goal will likely be to only provide const access to the global configuration data. Just make sure that mutators (including non const pointers) are not exposed via a header file.
The simple answer is what Thomas suggest, but correctly done (that is, not causing undefined behavior):
Create a mutable configuration object but pass it to the rest of the components by constant reference. When you create (and where you maintain) the real object you can change it, but the rest of the application won't be able to modify the config. A common pattern I have used in the past was:
class SomeObject {
Configuration const & config;
public:
SomeObject(Configuration const & config) : config(config) {}
void f() {
if (config.someParam()) { ...
// ...
void loadConfiguration(Config & config) { ... }
int main() {
Configuration config;
loadConfiguration(config); // config is a non-const &, can modify
SomeObject object(config); // object holds a const&, can only read
object.f();
// ...
This is not an answer to your question, just some observations to your code.
You don't need the typedef struct SerialNode { ... } SerialNode;, this is a c idiom. In c++, you just write struct SerialNode { ... }; and use SerialNode as a type name.
If you want to prevent a default constructor, make it private as you already do with the assignment operator
class SerialNode {
private:
SerialNode();
SerialNode &operator=(SerialNode&);
...
};
Don't use char* members, use std::string instead. C++ strings are much easier and safer to use than plain char pointers and the associated heap allocation.
Same goes for the map key; if you use std::string as a key, you don't need MapStrComp anymore, because std::string already provides an appropriate comparison.
Probably nicer is to wrap the whole thing in a singleton class:
class Config {
public:
static Config const& get() { return *config; }
static void load();
SerialNode const* operator[](const char*);
private:
static Config* config;
SerialMap map;
};
void Config::load() {
config = new Config();
// put things into it
}
Disclaimer: not tested, and haven't used C++ in a while, so there might be some syntax errors :)

C++ Class Common String Constants

In C++ I would like to define some strings that will be used within a class but the values will be common over all instances. In C I would have used #defines. Here is an attempt at it:
#include <string>
class AskBase {
public:
AskBase(){}
private:
static std::string const c_REQ_ROOT = "^Z";
static std::string const c_REQ_PREVIOUS = "^";
static std::string const c_REQ_VERSION = "?v";
static std::string const c_REQ_HELP = "?";
static std::string const c_HELP_MSG = " ? - Help\n ?v - Version\n ^^ - Root\n ^ - Previous\n ^Z - Exit";
};
int main(){AskBase a,b;}
If C++0x is needed that is acceptable.
You will have to define them separately in a single translation unit (source file), like so:
//header
class SomeClass
{
static const std::string someString;
};
//source
const std::string SomeClass::someString = "value";
I believe the new C++1x standard will fix this, though I'm not entirely sure.
When I need string constants within a class, I never put them in the class itself, but either:
1) If they need to be exposed in the header, I put them outside of the class (in a namespace if appropriate), like this:
const char * const c_REQ_ROOT = "^Z";
...
2) If not, I put them in the cpp file, in an anonymous namespace.
You can then even group strings constant from several related components in the same header file.
It may be not the most "academic" way, but the code is simpler and easier to refactor. I never found any actual advantage of defining string constant as static class members.
I'm really interested by the opinion of other programmers here, so do not hesitate to leave your comments.
I would never use that construction.
If one of the developers refactors the code and starts writing:
// header
class StringBug
{
static const std::string partOfTheString;
static const std::string wholeString;
};
// source
const std::string StringBug::partOfTheString = "Begin ";
const std::string StringBug::wholeString = partOfTheString + "and the rest";
You have a very hard to find bug in the program because there is no garante that partOfTheString is initialized before it is used for the creation of wholeString;
If I want to create class common string I do it like this:
// header
class StringBug
{
static const std::string& partOfTheString() {
static const std::string sPartOfTheString("Begin ");
return sPartOfTheString;
}
static const std::string& wholeString() {
static const std::string sWholeString( partOfTheString() + "and the rest");
return sWholeString;
}
};
According to the Wikipedia article this should be supported in C++0x however I can't find the reference in the State of C++ Evolution page.