两个模板类型的sizeof,两者都来自一个基础

For*_*veR 7 c++ c++11

示例代码

#include <iostream>

struct base {};

template<typename Type>
struct left : base {

   Type value;
};

template<typename Type>
struct right : base {

   Type value;
}; 

int main() {
   std::cout << "sizeof left<base> = " << sizeof(left<base>) << std::endl;
   std::cout << "sizeof left<right<base>>    = " << sizeof(left<right<base>>) << std::endl;
   std::cout << "sizeof left<right<left<right<left<base>>>>> = " << sizeof(left<right<left<right<left<base>>>>>) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

产量

GCC 4.6是

sizeof left<base> = 2  
sizeof left<right<base>>    = 3  
sizeof left<right<left<right<left<base>>>>> = 6
Run Code Online (Sandbox Code Playgroud)

用clang 3.1

sizeof left<base> = 2  
sizeof left<right<base>>    = 3  
sizeof left<right<left<right<left<base>>>>> = 6
Run Code Online (Sandbox Code Playgroud)

随着MSVC 2012

sizeof left<base> = 1
sizeof left<right<base>>    = 1
sizeof left<right<left<right<left<base>>>>> = 1
Run Code Online (Sandbox Code Playgroud)

所以,问题是,它是GCC/clang中的错误,还是实现定义,或者是正确的输出(来自标准的引用,或者这种行为的解释会很好)

Die*_*ühl 3

相关引用是 1.8 [intro.object] 第 6 段:

除非对象是位域或大小为零的基类子对象,否则该对象的地址是它占用的第一个字节的地址。如果两个非位域对象是另一个的子对象,或者至少一个是大小为零的基类子对象并且它们属于不同类型,则两个对象可能具有相同的地址;否则,它们应具有不同的地址。

在您的right<T>left<T>对象中(为什么必须使用不同的类模板?一个应该就足够了),您每个人都有一个成员value(类型为T)。每个人都需要有自己独特的地址。因此,

sizeof(left<right<left<right<left<base>>>>>) == 1
Run Code Online (Sandbox Code Playgroud)

肯定是错误的!有 6 个不同的对象:

  • 5value
  • left<right<left<right<left<base>>>>>

并且只有left<right<left<right<left<base>>>>>和它的一个主题(如果我记得其他规则,第一个value)可以共享地址。也就是说,对象的大小至少需要为 5。由于对象在对齐时效果最佳,因此似乎会填充到 6 字节(这很奇怪;我希望它会填充到 4 的倍数)。

甚至大小也left<base>不可能1:已经涉及两个base对象了!基类对象的基类形式lef<base> and one in form of a member of this class. These two需要不同的地址,因此大小至少需要为 2。

无论如何,对象大小仅要求它们至少有多大。他们没有任何要求,即它们不能大于某物。这被认为是实施质量问题。基于此,唯一错误的编译器(假设大小引号确实正确)是 MSVC++。其他尺寸有时可能比所需的稍大,但这不是错误。