sizeof运算符是否更喜欢对象而不是类型?

13
#include <iostream> 

int C; 

class C { 
  private: 
    int i[2]; 
  public: 
    static int f() { 
        return sizeof(C); 
    } 
}; 

int f() 
{ 
    return sizeof(C); // why the C can't be the class type C.
} 

int main() 
{ 
   std::cout << "C::f() = " <<C::f() << "," 
             << " ::f() = " <<::f() << std::endl; 
} 

上面的代码返回:C::f() = 8, ::f() = 4 我的问题是为什么全局函数f内部的标识符C解析为具有名称C的int类型对象,而不是类类型Csizeof是否具有特定的名称查找规则?
结论:从我在https://dev59.com/e3RB5IYBdhLWcg3weHLx#612476中阅读到的内容来看,通过函数/对象/枚举器名称隐藏类名是出于与C兼容性的考虑。为避免这种意外的隐藏,应该使用typedef将类强制编译器报错。

sizeof 是用于对象的。类类型 C 不是一个对象,而是类的实现。如果你想让全局函数 f() 调用类类型 C 的对象,你需要初始化一个实例,例如 C C; - R Nar
10
sizeof被用于对象上并不一定正确。根据cppreference的描述,sizeof可以查询对象或类型的大小。 - jaggedSpire
3个回答

21

sizeof不是这个问题的关键,它只是一些可以用于类型名称或变量名称的东西。这些规则也适用于标识符的其他用途。

§9.1 [class.name] (c++ standard draft n3797):

  1. ...snip... 如果在声明与同名变量、函数或枚举器的范围内声明类名,则当两个声明都在范围内时,只能使用 elaborated-type-specifier 引用类。

有一个名为C的类和同名的变量在全局范围内。因此,只能使用 elaborated type specifier (class C) 引用该类。

然而,在C的定义内部,该段落的第一部分是相关的:

§9.1 [class.name]:

  1. 类声明将类名引入其声明所在的作用域,并隐藏封闭作用域中的任何类、变量、函数或其他声明...snip...

§9 [class]:

  1. ...snip... 类名还插入到类本身的作用域中;这称为注入类名 ...snip...

因此,在class C的作用域内,注入的类名会隐藏外部作用域中的int C声明。因此,您可以引用C而不需要 elaborated type specifier。要引用全局的 int C,您可以使用 ::C


1
很棒的答案!我也发现https://dev59.com/e3RB5IYBdhLWcg3weHLx#612476这篇文章非常有用。 - Rich
那个答案解释了为什么这些规则对于与C的向后兼容性是必要的。不错的发现。 - eerorika

3

关于您的问题,sizeof没有任何特殊的解析或评估规则。

请考虑以下内容:

#include <iostream>
#include <typeinfo>

int C; 

class C { 
public:
    int i[2]; 
}; 

int main() 
{ 
   // compiles fine:
   int x = C;

   // prints 0:
   std::cout << C << "\n";

   // prints something that corresponds to "int"
   // (or even "int" itself):
   std::cout << typeid(C).name() << "\n";
}

在这三种情况下,C 被视为 int 变量而不是类型名称。
如果需要明确区分,您可以始终使用 class C:
#include <iostream>
#include <typeinfo>

int C; 

class C { 
public:
    int i[2]; 
}; 

int main() 
{ 
   // prints something that corresponds to "class C"
   // (or even "class C" itself):
   std::cout << typeid(class C).name() << "\n";

   // prints sizeof(int):
   std::cout << sizeof(C) << "\n";

   // prints sizeof(int) * 2:
   std::cout << sizeof(class C) << "\n";
} 

对象名称是否隐藏用户定义的类型名称(类、联合、枚举)?函数名称呢?对象名称是否也会隐藏函数或反之亦然?函数名称是否也会隐藏用户定义的类型名称? - Rich

1
尝试编译此代码将为您提供答案。
#include <iostream>

int C;

class C {
    int i[2];
  public: 
    static int f() { 
        return sizeof(C); 
    }
}; 

int f() { 
    return sizeof(C); // why the C can't be the class type C.
} 

int main() {
   C a; // <-- Adding this line generates the error
   std::cout << "C::f() = " <<C::f() << "," 
             << " ::f() = " <<f() << std::endl; 
} 

prog.cpp:22:4: error: must use 'class' tag to refer to type 'C' in this scope
   C a;
   ^
   class 
prog.cpp:3:5: note: class 'C' is hidden by a non-type declaration of 'C' here
int C; 
    ^
1 error generated.

编译器:

clang version 3.7.0 (tags/RELEASE_370/final 246979)
Target: x86_64-unknown-linux-gnu
Thread model: posix

获取正确的输出:
int f() { 
    return sizeof(class C);
} 

2
你使用的是哪个编译器?在启用警告的 g++ 4.8.4 下,它不会生成任何错误。 - Rich
它是在ideone上编译的,没有说明使用了哪个编译器,但我猜测是clang。我马上会澄清。 - smac89

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接