我在这里有一个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());
如何阻止这样的事情被允许?
答案 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实例。