具有私有构造函数和自身静态数组的类
Class with private constructor and static array of itself
抱歉,如果标题令人困惑,我找不到一种简单的方法来用简单的句子来写它。无论如何,我面临的问题:
// header:
class SomeThing
{
private:
SomeThing() {} // <- so users of this class can't come up
// with non-initialized instances, but
// but the implementation can.
int some_data; // <- a few bytes of memory, the default
// constructor SomeThing() doesn't initialize it
public:
SomeThing(blablabla ctor arguments);
static SomeThing getThatThing(blablabla arguments);
static void generateLookupTables();
private:
// declarations of lookup tables
static std::array<SomeThing, 64> lookup_table_0;
static SomeThing lookup_table_1[64];
};
getThatThing
函数旨在从查找表返回实例。
// in the implementation file - definitions of lookup tables
std::array<SomeThing, 64> SomeThing::lookup_table_0; // error
SomeThing Something::lookup_table_1[64]; // <- works fine
我只是不能使用Something
的std::array
,除非我在类中添加一个公共 ctor SomeThing()
。它适用于旧式数组,我可以定义数组,并在SomeThing::generateLookupTables()
函数中填充它。显然,std::array<SomeThing, 64>
类型没有构造函数。关于如何使其工作的任何想法,或者可能是这个概念的更好结构?
===
friend std::array<SomeThing, 64>
方法似乎是一个好主意,但是:
它也将在其他地方的数组中使用。我想保证这个类始终对外部用户保持某些不变性。使用此友好数组,用户可以意外地创建一个未初始化的SomeThing
数组。
此外,查找表是使用相当复杂的过程生成的,不能像std::array<SomeThing, 64> SomeThing::lookup_table_0(some value)
那样按内联完成
std::array<SomeThing, 64>
类在尝试定义实例时显然无法访问private
默认构造函数。您可以通过添加
friend class std::array<SomeThing, 64>;
到SomeThing
的定义.
解决方案:
std::array<SomeThing, 64> SomeThing::lookup_table_0 {{ }};
注意:如此处所述,{{}}
需要在 gcc 中对std::array
进行值初始化,而不会发出警告。 = {}
和{}
是正确的,但GCC还是警告了。
解决方案的关键是必须存在某种形式的初始值设定项。
首先进行术语检查:所有对象都以C++初始化。这有三种形式,默认值、值和零。没有"未初始化"的对象;没有显式初始值设定项的对象称为默认初始化。在某些情况下,这意味着对象的成员变量可能是不确定的("垃圾")。
无初始值设定项版本有什么问题?首先,std::array<SomeThing, 64>
的构造函数被定义为已删除,因为声明std::array<SomeThing, 64> x;
格式不正确(当然,由于缺少可访问的默认构造函数SomeThing
)。
这意味着任何尝试使用默认构造函数进行std::array<SomeThing, 64>
的代码反过来都是格式错误的。定义:
std::array<SomeThing, 64> SomeThing::lookup_table_0;
尝试使用默认构造函数,因此格式不正确。但是,一旦开始引入初始值设定项,std::array
的默认构造函数就不再起作用;由于std::array
是一个聚合,因此会发生聚合初始化,从而绕过隐式生成的构造函数。 (如果有任何用户声明的构造函数,那么它将不再是聚合)。
带有初始值设定项的版本由于 [dcl.init]/13 (n3936) 而工作:
静态成员的初始值设定项位于成员类的范围内
列表初始化的定义在这里将{ }
转换为{ SomeThing() }
。
由于您的构造函数是私有的,因此std::array
不能使用它。
您可以在SomeThing
中添加friend class std::array<SomeThing, 64>;
以授予对构造函数的访问权限。
另一种方法是使用可用的公共构造函数来初始化数组的元素:
std::array<SomeThing, 64> SomeThing::lookup_table_0{
SomeThing(blablabla_ctor_arguments), ..
};
编辑:
如果你有移动或复制构造函数可用,你甚至可以这样做:
std::array<SomeThing, 64> SomeThing::lookup_table_0{ SomeThing() };
以初始化整个数组默认值。
- C++17中函数模板中的静态数组初始化(MSVC 2019)
- 静态数组的自由动态数组
- 如何在C++中删除静态数组?
- 为什么 &a 和 c++ 中的静态数组相同?
- 为什么静态数组成员变量在调用对象的实例后不显示任何内容?
- C++ 返回指向函数内定义的静态数组的指针是否有效?
- 将在堆栈上声明的元素添加到静态数组
- const_cast静态数组以添加恒常性
- 动态分配的数组和静态数组之间的区别
- C++编译时使用 constexpr 字符数组指针分配静态数组?
- 我可以使用 constexpr 函数声明一个静态数组吗?
- 使用 lambda 初始化静态数组
- 为什么从函数返回数组时需要将数组声明为静态数组.(C++)
- 根据模板值确定的静态数组大小
- 如何使用 PHP-CPP 在 PHP 类中添加静态数组
- 包含不同大小静态数组的类的多个实例
- 从我的对象返回静态数组
- 如何避免在类中显式指定静态数组的大小
- 编译类型的时静态数组
- 来自函数参数的 C++ 静态数组声明