Правильный сеттер и геттер для статической переменной-члена в библиотеке только для заголовков


У меня есть несколько небольших библиотек только для заголовка (важна только часть заголовка). В начальных версиях у меня были некоторые статические члены в классах, определенных в них. Только позже (когда я использовал их в более крупном проекте) мне пришло в голову, что статические члены нарушат ODR. Я хотел, чтобы они были только заголовочными, поэтому определял статические члены отдельно .о файле cpp не могло быть и речи. Одним из хорошо известных решений является использование функции Мейерса синглтона - локальной статическая переменная для каждого статического элемента (как предложено, например, здесь).

Это все хорошо, но поскольку я хочу, чтобы синглет вел себя как членпеременной , я хочу иметь возможность получить и установить значение с помощью сеттеров и геттеров. Но как выглядят геттеры и сеттеры для функций Meyers singletons-локальные статические переменные? Я не смог найти никакого решения этой конкретной проблемы.

Чтобы пояснить, это требования:

  • мне нужно поведение статической переменной-члена внутри библиотекитолько для заголовка (поэтому я не могу поместить определения в A .cpp файл)
  • мне нужен геттер, который является только геттером (я не должен быть в состоянии изменить Значение, назначив ссылку, возвращаемую геттером)
  • я также хочу иметь возможность изменять значение через специальный сеттер.

Правка 1:

Я хотел бы ... объясните , Почему вам это может понадобиться.

Статические переменные в библиотеках, о которых я упоминал, определяют значенияпо умолчанию для некоторых параметров. Однако вместо того, чтобы жестко кодировать эти значения по умолчанию, я хочу дать пользователю возможность установить значения по умолчанию в начале программы, чтобы им не приходилось передавать значения вручную каждый раз, когда они вызывают функцию-член или создают новый экземпляр.

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

1 3

1 ответ:

Решение

#include <iostream>

class Foo
{

    private:

        static int& val()
        {
            static int v = 0;
            return v;
        }

    public:

        Foo()
        {
            set_val(14);
        }

        Foo(const int _v)
        {
            set_val(_v);
        }

        // The setter uses the fact that val()
        // returns a non-const reference,
        // so we can assign to it.
        static void set_val(const int _v)
        {
            val() = _v;
        }           

        // A true getter.
        // Returns const int&, so we cannot assign to it.
        static const int& get_val()
        {
            return val();
        }
};

int main(void)
{

    std::cout << "val is " << Foo::get_val() << "\n";
    Foo f1; // Set the value implicitly via an object constructor
    std::cout << "val is " << Foo::get_val() << "\n";
    Foo f2(5); // Set the value explicitly via an object constructor
    std::cout << "val is " << Foo::get_val() << "\n";
    Foo::set_val(42);
    std::cout << "val is " << Foo::get_val() << "\n";
    // Foo::get_val() = 4; // Doesn't compile, as required

    return 0;
}

Вывод:

val is 0
val is 14
val is 5
val is 42

Установка значения через конструкторы может (и, вероятно, должна) быть опущена. Я просто хотел показать, что это можно сделать. Это много кода только для одной переменной, но не настолько больше, чем для нестатического члена.

Любые мысли, комментарии и предложения приветствуются!