Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: Header-only project, static const non-integral

Tags:

c++

I have a header-only project. Inside it I have a class. Inside it (or anywhere else actually) I would like to have constant data (enum values to string and vice-verse). This problem seems a lot harder that I expected.

typedef boost::bimap<MyEnum,std::string> Data;

What I tried and did not work:

  1. static Data const s_data = _initData();: Error is like: only static const integral data members can be initialized within a class.

  2. static Data const * const s_pData = _initData();: The _initData() function had a static local variable (which became filled on first call), and returned the address of it. Did not work with the same reason as above.

What I tried and worked, but I consider it ugly:

class Ugly {
public:
    static MyEnum lookupByName(std::string s)
    {
        MyEnum ret;
        lookup(ret,s,true);
        return ret;
    }
    static String lookupByEnum(MyEnum e)
    {
        std::string ret;
        lookup(e,ret,false);
        return ret;
    }
    static void lookup(MyEnum &e, std::string &s, bool etos)
    {
        static Data s_data = _fill();
        if(etos)
            s = /* ... */;
        else
            e = /* ... */;
    }
    static Data _fill(){ /* ... */ };
};

Ideas?

like image 326
Notinlist Avatar asked Mar 08 '13 12:03

Notinlist


1 Answers

The simpler is

static T& global_t()
{ static T z = initializer; return z; }

global_t() can be used whereve a T value is required.

NOTE: In answer to rioki comment, we must also specify the function as inline if it is at global or namespace level (to avoid the "multiple instances" problem towards the linker).

The inline keyword is not necessary if the function is a template or is a class member-function (for which the inline definition is by default)

If the static T instantiation must be shared among different OS modules (read: DLLs) rioki is perfectly right, but -at that point- a header-only library makes no more sense.


Starting from C++17, the inline specifier can also be used on variables.

So, from C++17 onward, you can just write

inline T global_object = initializer;

You can also use inline for static members of function, to provide inline initialization, like

class Class
{
    static inline Type static_object_name = initializer;
};
like image 131
Emilio Garavaglia Avatar answered Sep 25 '22 13:09

Emilio Garavaglia