tags:

views:

849

answers:

4

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.

+9  A: 

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.

coppro
Note that this is how you have to initialize ANY static member that is not a built-in type (e.g. int, bool, double, etc).
Tyler McHenry
I heard they currently review it: The state of affairs is that you can only directly initialize in-class literal types with an integral constant expression (literal types have a constexpr ctor and such stuff - so, no std::string) - that concerning static data members. You may initialize arbitrary non-static members directly in-class, though, and the initialization may have side effects too.
Johannes Schaub - litb
A: 

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;
    }
};
TimW
Horrible performance! One method call to get a static compile-time known string!
Jaywalker
Most of the time it has got nothing to do with performance but with code safety. There are coding conventions that include this construct in a guideline and only if you can justify the performance part you can ignore the guideline.
TimW
A: 

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.

Motti
+1  A: 

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.

Jem
I agree since they are private I would put them in an anonymous namespace in the cpp files and keep them out of the header, then a change to the structure of the constants doesn't force a recompile of the client code.
iain