I have a few small header-only libraries (the header-only part is important). In the initial versions, I had some static members in the classes defined therein. It didn't occur to me until later (when I used them in a bigger project) that the static members would violate the ODR. I wanted to keep them header-only, so defining the static members in a separate .cpp file was out of the question. One well-known solution is to use a Meyers singleton function-local static variable for each static member (as suggested, for example, here).
That is all well and good, but since I want the singleton to behave like a member variable, I want to be able to get and set the value using setters and getters. But what do getters and setters for Meyers singletons function-local static variables look like? I haven't been able to find any solutions to that particular problem.
To clarify, these are the requirements:
EDIT 1:
I would like to explain why you might need this.
The static variables in the libraries I mentioned define the default values for some parameters. However, rather than hard-coding these default, I want to give the user the option to set the default values at the beginning of the program so they don't have to pass the values manually each time they call a member function or construct a new instance.
Also, although I agree that the use of the term "Meyers singleton" in the example provided here is misleading (I'm just using an int
value), there is nothing stopping you from using this paradigm with custom classes which you only want a single instance of. In such cases, the "Meyers singleton" term would be justified.
EDIT 2:
This has become somewhat irrelevant with the introduction of inline static
members in C++17, but I'll leave it up for people who don't have the option to use C++17.
#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;
}
Output:
val is 0
val is 14
val is 5
val is 42
Setting the value via constructors can (and probably should) be omitted. I just wanted to show that it can be done. This is a lot of code just for one variable, but not that much more than for a non-static member.
Any thoughts, comments and suggestions welcome!