具有私有构造函数和自身静态数组的类

时间:2014-12-30 00:37:27

标签: c++ c++11 initialization static-initialization stdarray

对不起,如果标题令人困惑,我找不到一个简单的方法来写一个简单的句子。无论如何,我面临的问题是:

 // 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)

3 个答案:

答案 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() }