这里发生了什么?我失去了常量吗?

时间:2011-06-16 20:49:10

标签: c++ c++11

我在这里有一个Singleton类,旨在由想要使用它的类继承。但我对编译器允许的内容有疑问,我不明白为什么:

template<class DerivedT>
class Singleton {
  static DerivedT*& internalPointer() {
    static DerivedT* object(nullptr);
    return object;
  }

  void reassignIf(Singleton* instance) {
    auto& object(internalPointer());
    if (object == static_cast<DerivedT*>(instance)) {
      object = static_cast<DerivedT*>(this);
    }
  }

  Singleton(Singleton const& other); // = delete

  Singleton& operator=(Singleton const& other); // = delete

public:
  static DerivedT* instance() { return internalPointer(); }

protected:
  Singleton() { reassignIf(nullptr); }

  Singleton(Singleton&& other) { reassignIf(&other); }

  ~Singleton() {
    auto& object(internalPointer());
    if (object == static_cast<DerivedT*>(this)) {
      object = nullptr;
    }
  }

  Singleton& operator=(Singleton&& other) { reassignIf(&other); return *this; }
};

class SingletonMock: Singleton<SingletonMock> {
public:
  using Singleton<SingletonMock>::instance;

  SingletonMock() : Singleton<SingletonMock>() { }
};

int main() {
  SingletonMock x;
  SingletonMock const y;  // why is this line allowed?
}

为什么允许底线? Singleton基类有一个名为internalPointer的静态成员函数,它具有静态DerivedT *。这应该成为SingletonMock *,但它允许将const SingletonMock分配给该变量。

编辑:

我想我理解为什么它现在从评论中发挥作用。但是,特别是允许我这样做:

SingletonMock const y;
SingletonMock* yPtr(SingletonMock::instance());

如何阻止这样的事情被允许?

3 个答案:

答案 0 :(得分:6)

C ++允许该行。规范说(8.5p9):

  

如果没有为对象指定初始化程序,并且该对象属于(可能是cv限定的)非POD类类型(或   其数组),对象应默认初始化; 如果对象是const限定类型,则为底层   类类型应具有用户声明的默认构造函数。

(强调我的)。 C ++ 0x(FDIS)措辞(8.5p6和8.5p11):

  

如果没有为对象指定初始化程序,则默认初始化该对象;

     

如果程序要求对const限定类型T的对象进行默认初始化,则T应为具有用户提供的默认构造函数的类类型。

答案 1 :(得分:3)

为什么不允许?单身似乎与你的问题无关

修改现在我明白了。这就是g ++ - 4.6对这颗珍珠所说的话:

g++-4.6 --std=c++0x -O2 t.cpp -o t
t.cpp: In function ‘int main()’:
t.cpp:65:25: error: uninitialized const ‘y’ [-fpermissive]
t.cpp:56:7: note: ‘const class SingletonMock’ has no user-provided default constructor
t.cpp: In destructor ‘Singleton<DerivedT>::~Singleton() [with DerivedT = SingletonMock]’:
t.cpp:56:7:   instantiated from here
t.cpp:43:9: error: ‘Singleton<SingletonMock>’ is an inaccessible base of ‘SingletonMock’
t.cpp: In member function ‘void Singleton<DerivedT>::reassignIf(Singleton<DerivedT>*) [with DerivedT = SingletonMock, Singleton<DerivedT> = Singleton<SingletonMock>]’:
t.cpp:32:9:   instantiated from ‘Singleton<DerivedT>::Singleton() [with DerivedT = SingletonMock]’
t.cpp:56:7:   instantiated from here
t.cpp:13:9: error: ‘Singleton<SingletonMock>’ is an inaccessible base of ‘SingletonMock’
t.cpp:15:13: error: ‘Singleton<SingletonMock>’ is an inaccessible base of ‘SingletonMock’

它需要一些刺激来接受这个代码,这确实不是标准的代码。


原创,无聊的答案,只是为了好玩:)

  

只允许订购声明说明符:

int main()
{
    int       x = 1;
    const int y = 2;
    int const z = 3;

    volatile const int a = 2;
    int volatile const b = 3;
    int const volatile c = 3;

    return z;
}

为了好玩,请参阅this example on codepad.org:_这些完全相同的变量声明(显然除了名称和初始化程序之外):

int main()
{
    volatile register const unsigned int v1 = 1;
    volatile register const int unsigned v2 = 2;
    volatile register unsigned const int v3 = 3;
    volatile register unsigned int const v4 = 4;
    volatile register int const unsigned v5 = 5;
    volatile register int unsigned const v6 = 6;
    volatile const register unsigned int v7 = 7;
    volatile const register int unsigned v8 = 8;
    volatile const unsigned register int v9 = 9;
    volatile const unsigned int register v10    = 10;
    volatile const int register unsigned v11    = 11;
    volatile const int unsigned register v12    = 12;
    volatile unsigned register const int v13    = 13;
    volatile unsigned register int const v14    = 14;
    volatile unsigned const register int v15    = 15;
    volatile unsigned const int register v16    = 16;
    volatile unsigned int register const v17    = 17;
    volatile unsigned int const register v18    = 18;
    volatile int register const unsigned v19    = 19;
    volatile int register unsigned const v20    = 20;
    volatile int const register unsigned v21    = 21;
    volatile int const unsigned register v22    = 22;
    volatile int unsigned register const v23    = 23;
    volatile int unsigned const register v24    = 24;
    register volatile const unsigned int v25    = 25;
    register volatile const int unsigned v26    = 26;
    register volatile unsigned const int v27    = 27;
    register volatile unsigned int const v28    = 28;
    register volatile int const unsigned v29    = 29;
    register volatile int unsigned const v30    = 30;
    register const volatile unsigned int v31    = 31;
    register const volatile int unsigned v32    = 32;
    register const unsigned volatile int v33    = 33;
    register const unsigned int volatile v34    = 34;
    register const int volatile unsigned v35    = 35;
    register const int unsigned volatile v36    = 36;
    register unsigned volatile const int v37    = 37;
    register unsigned volatile int const v38    = 38;
    register unsigned const volatile int v39    = 39;
    register unsigned const int volatile v40    = 40;
    register unsigned int volatile const v41    = 41;
    register unsigned int const volatile v42    = 42;
    register int volatile const unsigned v43    = 43;
    register int volatile unsigned const v44    = 44;
    register int const volatile unsigned v45    = 45;
    register int const unsigned volatile v46    = 46;
    register int unsigned volatile const v47    = 47;
    register int unsigned const volatile v48    = 48;
    const volatile register unsigned int v49    = 49;
    const volatile register int unsigned v50    = 50;
    const volatile unsigned register int v51    = 51;
    const volatile unsigned int register v52    = 52;
    const volatile int register unsigned v53    = 53;
    const volatile int unsigned register v54    = 54;
    const register volatile unsigned int v55    = 55;
    const register volatile int unsigned v56    = 56;
    const register unsigned volatile int v57    = 57;
    const register unsigned int volatile v58    = 58;
    const register int volatile unsigned v59    = 59;
    const register int unsigned volatile v60    = 60;
    const unsigned volatile register int v61    = 61;
    const unsigned volatile int register v62    = 62;
    const unsigned register volatile int v63    = 63;
    const unsigned register int volatile v64    = 64;
    const unsigned int volatile register v65    = 65;
    const unsigned int register volatile v66    = 66;
    const int volatile register unsigned v67    = 67;
    const int volatile unsigned register v68    = 68;
    const int register volatile unsigned v69    = 69;
    const int register unsigned volatile v70    = 70;
    const int unsigned volatile register v71    = 71;
    const int unsigned register volatile v72    = 72;
    unsigned volatile register const int v73    = 73;
    unsigned volatile register int const v74    = 74;
    unsigned volatile const register int v75    = 75;
    unsigned volatile const int register v76    = 76;
    unsigned volatile int register const v77    = 77;
    unsigned volatile int const register v78    = 78;
    unsigned register volatile const int v79    = 79;
    unsigned register volatile int const v80    = 80;
    unsigned register const volatile int v81    = 81;
    unsigned register const int volatile v82    = 82;
    unsigned register int volatile const v83    = 83;
    unsigned register int const volatile v84    = 84;
    unsigned const volatile register int v85    = 85;
    unsigned const volatile int register v86    = 86;
    unsigned const register volatile int v87    = 87;
    unsigned const register int volatile v88    = 88;
    unsigned const int volatile register v89    = 89;
    unsigned const int register volatile v90    = 90;
    unsigned int volatile register const v91    = 91;
    unsigned int volatile const register v92    = 92;
    unsigned int register volatile const v93    = 93;
    unsigned int register const volatile v94    = 94;
    unsigned int const volatile register v95    = 95;
    unsigned int const register volatile v96    = 96;
    int volatile register const unsigned v97    = 97;
    int volatile register unsigned const v98    = 98;
    int volatile const register unsigned v99    = 99;
    int volatile const unsigned register v100   = 100;
    int volatile unsigned register const v101   = 101;
    int volatile unsigned const register v102   = 102;
    int register volatile const unsigned v103   = 103;
    int register volatile unsigned const v104   = 104;
    int register const volatile unsigned v105   = 105;
    int register const unsigned volatile v106   = 106;
    int register unsigned volatile const v107   = 107;
    int register unsigned const volatile v108   = 108;
    int const volatile register unsigned v109   = 109;
    int const volatile unsigned register v110   = 110;
    int const register volatile unsigned v111   = 111;
    int const register unsigned volatile v112   = 112;
    int const unsigned volatile register v113   = 113;
    int const unsigned register volatile v114   = 114;
    int unsigned volatile register const v115   = 115;
    int unsigned volatile const register v116   = 116;
    int unsigned register volatile const v117   = 117;
    int unsigned register const volatile v118   = 118;
    int unsigned const volatile register v119   = 119;
    int unsigned const register volatile v120   = 120;

    return 0;
}

所有有效的C ++

答案 2 :(得分:0)

我认为问题是:为什么编译器允许我声明const Singleton?我假设您想知道当您只想要指向非const const Singleton的指针时,编译器如何让您创建Singleton。如果声明具有构造函数的类的const实例,则仍需要构造它。在那个构造函数中,它不是const。构造函数完成后,它只能作为const访问,但在构造时不适用。否则,您不能拥有任何类的const实例。