header-only 库中静态成员变量的正确 setter 和 getter
Proper setter and getter for static member variable in header-only library
我有一些小的 header-only 库(header-only 部分很重要)。在初始版本中,我在 类 中定义了一些静态成员。直到后来(当我在一个更大的项目中使用它们时)我才意识到静态成员会违反 ODR。我想保留它们 header-only,因此在单独的 .cpp 文件中定义静态成员是不可能的。一个 well-known 解决方案是为每个静态成员使用 Meyers 单例 function-local 静态变量(如建议的那样,例如 here)。
一切都很好,但由于我希望单例的行为像成员 变量,我希望能够使用 [=79] 获取和设置值=]s 和 getters。但是 Meyers 单例 function-local 静态变量的 getter 和 setter 是什么样子的呢?我一直没能找到那个特定问题的任何解决方案。
澄清一下,这些是要求:
- 我想要静态成员变量在header-only库中的行为(所以我不能把定义放在.cpp 文件)
- 我想要一个getter,它只是一个getter(我不应该修改 通过将值赋给 getter)
返回的引用
- 我还希望能够通过专用 setter.
修改值
编辑 1:
我想解释一下为什么您可能需要这个。
我提到的库中的静态变量为一些参数定义了默认值。然而,而不是 hard-coding 这些默认值,我想让用户选择在程序开始时设置默认值,这样他们就不必在每次调用成员函数时手动传递值或构造一个新实例。
此外,尽管我同意此处提供的示例中术语 "Meyers singleton" 的使用具有误导性(我只是使用 int
值),但没有什么可以阻止您使用这种带有自定义 类 的范例,您只需要一个实例。在这种情况下,"Meyers singleton" 术语是合理的。
编辑 2:
这与在 C++17 中引入 inline static
变量有些无关,但我会把它留给那些无法选择使用 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;
}
输出:
val is 0
val is 14
val is 5
val is 42
可以(并且可能应该)省略通过构造函数设置值。我只是想证明这是可以做到的。这是一个变量的大量代码,但 比非静态成员多 。
欢迎任何想法、意见和建议!
我有一些小的 header-only 库(header-only 部分很重要)。在初始版本中,我在 类 中定义了一些静态成员。直到后来(当我在一个更大的项目中使用它们时)我才意识到静态成员会违反 ODR。我想保留它们 header-only,因此在单独的 .cpp 文件中定义静态成员是不可能的。一个 well-known 解决方案是为每个静态成员使用 Meyers 单例 function-local 静态变量(如建议的那样,例如 here)。
一切都很好,但由于我希望单例的行为像成员 变量,我希望能够使用 [=79] 获取和设置值=]s 和 getters。但是 Meyers 单例 function-local 静态变量的 getter 和 setter 是什么样子的呢?我一直没能找到那个特定问题的任何解决方案。
澄清一下,这些是要求:
- 我想要静态成员变量在header-only库中的行为(所以我不能把定义放在.cpp 文件)
- 我想要一个getter,它只是一个getter(我不应该修改 通过将值赋给 getter) 返回的引用
- 我还希望能够通过专用 setter. 修改值
编辑 1:
我想解释一下为什么您可能需要这个。
我提到的库中的静态变量为一些参数定义了默认值。然而,而不是 hard-coding 这些默认值,我想让用户选择在程序开始时设置默认值,这样他们就不必在每次调用成员函数时手动传递值或构造一个新实例。
此外,尽管我同意此处提供的示例中术语 "Meyers singleton" 的使用具有误导性(我只是使用 int
值),但没有什么可以阻止您使用这种带有自定义 类 的范例,您只需要一个实例。在这种情况下,"Meyers singleton" 术语是合理的。
编辑 2:
这与在 C++17 中引入 inline static
变量有些无关,但我会把它留给那些无法选择使用 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;
}
输出:
val is 0
val is 14
val is 5
val is 42
可以(并且可能应该)省略通过构造函数设置值。我只是想证明这是可以做到的。这是一个变量的大量代码,但 比非静态成员多 。
欢迎任何想法、意见和建议!