Как иметь статические элементы данных в библиотеке только заголовка?

StackOverflow https://stackoverflow.com//questions/11709859

  •  13-12-2019
  •  | 
  •  

Вопрос

Какой лучший способ иметь статический элемент в классах без шаблонного библиотеки, Не размещая бремя определения участника на класс пользователя?

сказать, что я хочу предоставить этот класс:

class i_want_a_static_member
{
    static expensive_resource static_resource_;

public:
    void foo()
    {
        static_resource_.bar();
    }
};
.

Тогда пользователь класса не должен забывать определить статический член где-то (Как уже ответил Многие times ):

// this must be done somewhere in a translation unit
expensive_resource i_want_a_static_member::static_resource_;
.

У меня есть ответ ниже, но у него есть некоторые недостатки.Есть ли лучшие и / или более элегантные решения?

Это было полезно?

Решение

C ++ 17 и выше

Используйте переменные генеракодицетагкода для нединамической инициализации:

struct Foo
{
    inline static int I = 0;
};
.

и используйте функцию локальные статические переменные иначе:

struct Foo
{
    static std::string& Bar()
    {
        static std::string S = compute();
        return S;
    }
};
.

<Сильные> C ++ 14 и ниже

Используйте функцию локальной статики, так как они проще проще в использовании.

Если по какой-то причине вы действительно хотите для статического элемента данных , то вы можете использовать трюк шаблона:

template <typename T = void>
struct Foo
{
     static int I = 0; // inline initialization only for simple types.
};

template <typename T>
int Foo<T>::I;
.

на локальной статии

Для ресурсов, которые требуют динамической инициализации, лучше всего использовать локальный статический.

Порядок, в котором файл-охватывает или статистика схватки классов динамически инициализированы не определены, в целом, что приведет к статическому инициализации заказа Fiasco, когда вы пытаетесь прочитать неинициализированную статическую в рамках инициализации другого. Местный статический решают проблему, будучи инициализированным лениво, при первом использовании.

Есть несколько легких накладных расходов для использования локальной статики. От C ++ 11 инициализация требуется для безопасного потока, что обычно означает, что любой доступ устанавливается атомной прочитанной и просвещенной веткой.

Другие советы

Мое собственное решение состоит в том, чтобы использовать класс держателя для шаблонов, поскольку статические элементы работают нормально в шаблонах, и используют этот держатель в качестве базового класса.

template <typename T>
struct static_holder
{
    static T static_resource_;
};

template <typename T>
T static_holder<T>::static_resource_;
.

Теперь используйте класс держателя:

class expensive_resource { /*...*/ };

class i_want_a_static_member : private static_holder<expensive_resource>
{
public:
    void foo()
    {
        static_resource_.bar();
    }
};
.

Но как имя участника указано в классе держателя, вы не можете использовать тот же держатель для более чем одного статического элемента.

как в C ++ 17. Теперь вы можете использовать встроенные переменные, чтобы сделать это:

static const inline float foo = 1.25f;
.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top