对不起,如果标题令人困惑,我找不到一个简单的方法来写一个简单的句子。无论如何,我面临的问题是:
// 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
除非我在课程中添加公共ctor std::array
,否则我无法使用Something
SomeThing()
。它适用于旧式数组,我可以定义数组,并在SomeThing::generateLookupTables()
函数中填充它。显然类型std::array<SomeThing, 64>
没有构造函数。关于如何使其发挥作用的任何想法,或者对于这个概念可能是更好的结构?
=============编辑=======
friend std::array<SomeThing, 64>
方法似乎是一个好主意,但是:
它也将在其他地方的数组中使用。我想保证这个课程始终保持某些不变量对外部用户。使用此友好数组,用户可能会意外地创建一个未初始化的SomeThing
数组。
此外,查找表是使用相当复杂的过程生成的,无法按内联方式完成,如std::array<SomeThing, 64> SomeThing::lookup_table_0(some value)
答案 0 :(得分:5)
std::array<SomeThing, 64>
类在尝试定义实例时显然无法访问private
默认构造函数。您可以通过添加
friend class std::array<SomeThing, 64>;
到SomeThing
的定义。
答案 1 :(得分:4)
由于您的构造函数是私有的,std::array
无法使用它。
您可以在friend class std::array<SomeThing, 64>;
中添加SomeThing
以授予对构造函数的访问权限。
另一种方法是使用可用的公共构造函数初始化数组元素:
std::array<SomeThing, 64> SomeThing::lookup_table_0{
SomeThing(blablabla_ctor_arguments), ..
};
编辑:
如果您有移动或复制构造函数,您甚至可以这样做:
std::array<SomeThing, 64> SomeThing::lookup_table_0{ SomeThing() };
让你的整个数组默认初始化。
答案 2 :(得分:4)
解决方案:
std::array<SomeThing, 64> SomeThing::lookup_table_0 {{ }};
注意:正如here所解释的那样,{{}}
需要在gcc中对std::array
进行值初始化而不发出警告。 = {}
和{}
是正确的,但gcc仍然会发出警告。
解决方案的关键是必须存在某种形式的初始化程序。
首先进行术语检查:所有对象都在C ++中初始化。有三种形式,默认,值和零。没有“未初始化”的对象;没有显式初始值设定项的对象称为 default-initialized 。在某些情况下,这意味着对象的成员变量可能是不确定的(“垃圾”)。
no-initializer版本有什么问题?首先,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() }
。