`sizeof`*真的*评估为`std :: size_t`吗?它可以?

Lig*_*ica 60 c++ std language-lawyer c++11

采取以下标准段落:

[C++11: 5.3.3/6]:结果sizeofsizeof...是类型的常量std::size_t.[注意: std::size_t在标准标题<cstddef>(18.2)中定义. - 尾注]

现在:

[C++11: 18.2/6]:该类型size_t是一个实现定义的无符号整数类型,其大小足以包含任何对象的字节大小.

当然,该段落并不要求这size_t是一个定义的类型别名typedef,但由于它明确声明可以通过标准标题提供<cstddef>,我认为我们可以认为如果没有包含它<cstddef>应该删除任何size_t可用的保证.一个程序.

但是,根据第一个引用,我们可以无论如何获得类型的表达式std::size_t.

我们实际上可以证明这两个事实:

int main()
{
    typedef decltype(sizeof(0)) my_size_t;

    my_size_t x   = 0;  // OK
    std::size_t y = 1;  // error: 'size_t' is not a member of 'std'
}
Run Code Online (Sandbox Code Playgroud)

std::size_t该程序不可见,但sizeof(0)仍然给我们一个?真?

因此,说它5.3.3/6有缺陷的,并且它实际上具有"与std::size_t解决的任何类型相同的类型",而不是 std::size_t它本身,这是不正确的吗?

当然,如果std::size_t是类型别名,这两个是同一个,但同样,这实际上是必需的.

Die*_*ühl 52

标准只是强制要求sizeof(expr)类型与std::size_t.没有任何使用sizeof(expr)使得名称std::size_t可用的任务,因为std::size_t只是命名其中一个内置的整数类型,没有真正的问题.

  • @LightnessRacesinOrbit:*类型*和*类型名称*之间存在差异.类型始终存在,但*name*不存在. (20认同)
  • @LightnessRacesinOrbit:嗯,这很直截了当,不是吗?您可以声明*names*,并且可以定义*types*.类型可以有许多名称,使用`typedef`或`using`声明,或者作为模板参数,但只有一个定义 - 它可以是内置的,也可以是用户定义的.并且traits仅适用于类型,而不是名称,因此没有特征可以告诉您某些内容是typedef还是主要名称. (6认同)
  • 无论如何,我认为这里的问题在于类型和名称之间的区别.可能存在一种类型,即使它是不可解的,也可以对表达式进行分类(参见lambdas).`sizeof(T)`与`std :: size_t`产生相同类型的事实与`std :: size_t`可能无法解释的事实(如果不包括`<cstddef>`)不冲突.拼写出`sizeof(T)`并不认为你可以"说"`std :: size_t`. (5认同)
  • @ H2CO3:不要忘记`std :: typeinfo`情况.和`std :: initializer_list` ...... (5认同)
  • @ H2CO3:大约30年前,这个想法在C语言中与varargs一起消失了.WG21从未认为这两者可能是完全分开的. (5认同)
  • @ H2CO3:请注意,从概念上讲,语言和库之间没有分离!这是一回事,语言功能可以根据我们可能认为的语言实现库或库功能来实现. (4认同)
  • @ H2CO3:将语言核心与库分离是一个毫无意义和随意的目标.你有什么收获?C++是一种由语法,语义和库组成的语言,就像任何其他语言一样. (4认同)
  • @LightnessRacesinOrbit:它有点像符号`1`:在你知道如何写它之前,你不能直接拼写它.仅仅因为你不知道如何拼写它并不意味着概念不存在. (3认同)
  • @GManNickG我不愿意进一步争论这个问题."你获得了什么" - 例如,编译器和库之间的可互换性.(你似乎是一位经验丰富的C++程序员.我很惊讶你发现这种"任意"和"毫无意义"...... (2认同)

Yak*_*ont 47

不要混淆地图的地图.

类型可以通过类型名称来命名.这些类型名称可以是内置的,也可以是用户定义的类型,或者它们甚至可以是template参数,并根据实例化引用多种不同的类型.

但名字不是类型.显然,标准并不要求所有类型都有名称 - 经典struct {}是没有名称的类型.

std::size_t是一个类型名称.它命名sizeof(expression)返回的类型.

编译器可以具有该类型的规范名称 - __size_t这将是它具有唯一内置规范类型名称的一种方式.

该条款中的标准保证无论何种类型sizeof(expression),一旦您#include <cstddef>,该名称std::size_t现在指的是该类型.

在标准中,它们按名称引用类型.他们没有说"此类型名称所指的类型",而只是说"$ NAME $类型".编译器可以决定它int是否是另一个名称,__int_32_fast标准也没有异议.

同样的事情发生在std::nullptr_tand std::initializer_list<Ts>std::type_info:使用这些类型的变量并不总是要求为您提供这些类型的名称的标题包含在您的程序中.

传统的C/C++内置类型都具有不需要标题的规范名称.缺点是这会破坏现有代码,因为全局范围中的新类型名称会与其他标识符冲突.

通过使用"无名类型",您可以通过包含头文件来获取它们的名称,我们可以避免这个问题.

  • @LightnessRacesInOrbit是的,措辞不一致.与`nullptr_t`相同 - 许多不一致的措辞.可能可以清理?但是非常深奥,值得努力吗? (2认同)

rod*_*igo 5

据我了解,此标准段落需要以下表达式:

typeid(sizeof(0)) == typeid(std::size_t)
Run Code Online (Sandbox Code Playgroud)

永远都会屈服true.如果使用实际标识符std::size_t,::size_t或者任何其他别名/ typedef将无关紧要,只要std::typeinfo::operator==()保留该类型的标识即可.

相同类型的身份问题出现在该语言的其他位置.例如,在我的64位机器中,由于函数重新定义,以下代码无法编译:

#include <cstddef>
void foo(std::size_t x)
{}

void foo(unsigned long x)
{}
Run Code Online (Sandbox Code Playgroud)

  • @LightnessRacesinOrbit:但是,你需要在需要特定类型的地方做同样的事情.我可以写`typedef int number; number main(){}`?如果是这样,3.6.1是否应该说"它[main]应该有一个int类型的返回类型(或者由其他名称给出的相同类型")? (3认同)

Kei*_*son 5

是.

产生的类型sizeof是一些无符号整数类型; 实现定义了它是哪一个.

例如,在某些特定实现中,sizeof表达式的类型可能是unsigned long.

std::size_t如果它是a typedef,只不过是另一个名字unsigned long.所以这两个陈述:

类型sizeof ...是类型的常量unsigned long

类型sizeof ...是类型的常量std::size_t

对于该实现正在说完全相同的事情.类型unsigned long和类型std::size_t是相同的类型.不同之处在于后者对于所有(符合标准)实现都是准确的,其中std::size_t可能是别名,例如,unsigned int或其他一些无符号类型.

就编译器而言,sizeof产生类型的结果unsigned long; 编译器(与运行时库相对)不需要任何名称知识size_t.

这一切都假设std::size_t(或者只是size_t你在谈论C)是一个typedef.这在C或C++标准中都没有说明.然而,通过制作size_ttypedef ,实现可以直接符合标准的要求.我不相信有任何其他便携方式来满足这些要求.(它不能是宏或实现定义的关键字,因为这会侵犯用户的名称空间,并且宏不会在std命名空间中作用域.)编译器可以创建size_t一些特定于实现的构造而不是typedef ,但由于typedef运行得非常好,所以没有必要这样做.如果标准声明size_t是typedef ,那将是很好的,恕我直言.

(一个不相关的旁边:真正的问题是标准将结果称为"常量".在ISO C中,"常量"是一个标记,例如整数文字.C++,据我所知,不是'定义名词"常量",但它确实引用了术语的ISO C定义.sizeof ...是一个常量表达式 ;它不是常量.调用结果"常量值"是合理的.)