为什么没有std :: is_struct类型特征?

Jep*_*sen 56 c++ type-traits c++11

我已经看到,为了检查类型T是否是我可以使用的类:

bool isClass = std::is_class<T>::value;
Run Code Online (Sandbox Code Playgroud)

它对类和结构都返回true.我知道在C++中它们几乎是一样的,但我想知道为什么在类型特征中它们之间没有区别.检查这种差异总是没用,还是有一些我不理解的理由?

Lig*_*ica 167

它对类和结构都返回true.我知道在C++中它们几乎是一样的,但我想知道为什么在类型特征中它们之间没有区别.

不幸的是,这是C++中常见的误解.有时它来自于基本的误解,但有时它来自于英语的含糊不清.它可能来自不准确的编译器诊断,写得不好的书,不正确的SO答案......

你可能读过这样的东西:

"除了成员和基础的默认可见性之外,结构和类之间的C++没有区别."

这段经文可以被误解,因为在使用诸如"无差异"之类的短语时,很难区分身份平等的概念.

事实上,自1985年以来,C++还没有结构.它只有类.

您使用关键字class和关键字声明的类型struct.期.关键字struct和使用该关键字定义类时默认的可见性规则只是为了与C ...向后兼容而保留,但这是一种语法.它不会使得到的类型实际上是另一种类型.

类型特征没有区别,因为字面意思不是一个要做的.

  • @WarrenP:[C++不包含"C"(http://stackoverflow.com/a/8594186/560648).C++中类的定义非常清楚.C++没有结构.我要说的全部内容是关键字`struct`创建类,而不是结构.你的断言_"因此结构是一个C++特性"_是一个不合理的,我害怕. (66认同)
  • @WarrenP:它没有_实现C实现的所有东西.例如,它不实现可变长度数组或结构._"是一个结构(当在C++源文件中使用时),没有成员方法,并且被使用,因为可以使用C结构,比如,一个打包的位字段,不再是结构,尽管它的功能与用于编码一系列位域的C结构?"_这是正确的.这是一堂课.`std :: is_class`特性的行为使得这一点非常清楚. (16认同)
  • C++有结构,因为它包含C,它有结构.有零个C++编译器不接受struct关键字.因此struct是一个C++特性.从C获得它的事实不足以说明它不是C++特性.大括号也不是C++吗? (13认同)
  • @WarrenP:你必须问他.但是,考虑到他是1985年开始对CFront 2.0进行这一改变的人("一个结构是一个......"),我认为这是一个相当不错的选择. (9认同)
  • @VioletGiraffe:它没有,至少在GCC没有.如果其他一些编译器发出警告(例如我没有检查过MSVS),那么出于同样的原因你得到_any_警告:因为看起来你可能写了一些你不想要的东西.毕竟,为什么_would_你在两个关键词之间切换?然而,这将是一个更愚蠢的警告,因为这样的错误可能不会产生更少的后果. (9认同)
  • @ PeterA.Schneider:_"在C++中也没有字符,整数,浮点数或双精度数;也没有函数,指针或数组.没有if/then/else"_是的,有所有这些东西.但是没有结构.如果您认为这个答案"没有明确指出[我的意图"],您应该多读一遍,因为它非常清楚. (8认同)
  • @ PeterA.Schneider:我提交的每次出现都是一个编辑问题.标准很清楚`struct`声明了_class_.这是一个单一的概念.C++没有结构或结构.完全没有.随意编写自己的竞争答案,但我必须现在就去,并且无法进一步接受这个讨论. (8认同)
  • @ Cheersandhth.-Alf:呃,是的,确实......"**是一个班级**".谢谢你带给我典型的节日欢乐,Alf. (6认同)
  • 好吧,看看这个方式:"没有工会,只有班级".该标准将联合定义为类类型.但"没有工会"显然是无稽之谈.[哦,这揭示了这个答案中的次要错误:它将类类型限制为使用`struct`和`class`定义的类型.与那个断言相反,"联盟"也是一个阶级.总而言之,这个答案是彻头彻尾的废话.] (6认同)
  • @ Jean-MichaëlCelerier:问题是关于C++,而不是MS Windows.依赖于特定平台上的实现细节的C++开发人员,无论是否实现,不仅仅是在C++中开发.我很乐意对另一个询问实施差异的问题给出不同的答案. (6认同)
  • @Alex因为它是一个类,而不是一个结构! (5认同)
  • @kralyk:不,它没有.如上所述.您是否有任何实质内容可以添加到讨论中? (5认同)
  • ** - 1**"实际上,自1985年以来,C++还没有结构.它只有类."这是错误的.例如C++11§9/ 8定义"A*标准布局结构*是用*class-key*`struct`或*class-key*`class`定义的标准布局类(这里的区别)在*struct*和*union*类类型之间. (5认同)
  • 这个答案在MS Windows上是错误的:使用`struct`关键字声明的类型与使用`class`关键字声明的类型具有不同的名称.[例如](https://godbolt.org/g/aGXhno)带结构`void f(const foo&)`的函数被修改为`?f @@ YAXABUfoo @@@ Z`和函数把一个类`void g(const bar&)`修改成`?g @@ YAXABVbar @@@ Z`.(注意函数名称前的U/V).如果您只使用前向声明发送标头并且实现是另一种类型(缺少符号等),这会产生影响. (5认同)
  • 那么,当前的ISO C++标准是使用关键字"struct"定义的类型的"结构"和"结构类型".所以当你说"事实上,C++自1985年以来就没有结构"; "无结构"的意思是:"没有结构".因为C++在共同语言中具有关键字和标准,所以具有明确的结构.因此,我假设您要强调,尽管语法和语义相似,但设计上,C和C++是不同的语言,在某种程度上类似于`struct`或`int`这两种语言具有相同的名称仍然不同. (4认同)
  • 你很搞笑.因此关键字`struct`具有误导性(因为它没有定义一个),标准充满了错误,人们使用的语言不正确且编写得很糟糕.我知道了. (4认同)
  • @Alex:C++没有结构体.C++有类.在C++中,`struct`引入了_class_.这就是重点. (4认同)
  • @kralyk:通过这种逻辑,我们可以为事物编制随机名称并声称我们是对的.C++没有独角兽?当然可以!但它称他们为班级.POD确实是C++与C所谓的结构最接近的概念,但POD类仍然是类.你似乎对这个命名很重要,但是在一个问题为什么没有一个名为`is_struct`的特征的问题上,我认为这确实很重要.因为这确实是问题所在. (4认同)
  • @BarryTheHatchet对我来说,情况正好相反.每当你使用关键字`class`时,你实际上是在声明一个`struct`.标准提到的课程是编辑性的邋..C++自1979年以来就没有类(结构的新同义词由Bjarne引入以获得资金 - 听起来很时髦).那不是我的错,也不是我的问题.:-) (3认同)
  • @kralyk:这完全没有意义.C++没有独角兽,但它有结构?是什么让独角兽不如结构特别?你对这个主张的唯一辩护就是"`is_class` _could_已经``is_struct`".但事实并非如此!就像它不是'is_unicorn`.那你继续谈谈其他一些不相关的语言......? (3认同)
  • @LightnessRacesinOrbit不,你还没有回答当你说_"语言X有/没有结构"时的含义.(这是我第三次问.)你应该把这个编辑成你的答案,因为否则没人知道你的意思.除非你澄清,否则没有太多的同意/不同意.哦,顺便说一下,我刚刚在§3.2的标准中找到了这一行:`struct X; //将X声明为结构类型`我认为非常清楚. (3认同)
  • 它几乎实现了C实现的所有功能,包括结构可以做的所有事情,然后提供设施呢?那么,它包含Struct,而struct是C++的一部分.是一个结构(当在C++源文件中使用时),没有成员方法,并且被使用,因为可以使用C结构,比如填充的位字段,不再是结构,尽管它的功能与C相同struct用于编码一系列位字段? (2认同)
  • 我从没想过这样.这是他的圣洁,Bjarne也会解释它吗? (2认同)
  • 如果是这样,那么为什么将类型正向声明为`struct`并将其实际定义为`class`,反之亦然,会产生编译器警告(如果不是错误)? (2认同)
  • @LightnessRacesinOrbit Unicorns在C++标准中没有被定义为C++中的东西,但结构为_are_.就这么简单.我提到了其他语言,因为它们也有结构,__正如C++ has_,并且因为它们的结构与C的结构不同,_就像在C++中一样.我希望现在更清楚了. (2认同)
  • @kralyk:我已经解决了这些问题中的每一个问题; 我不会再重复这个了.让我们接收有差异的看法.随意写一个竞争的答案. (2认同)
  • @Marc.2377 其实我愿意!通常是当我没有真正添加任何成员时的异常类型,或者 PODdy 的东西。 (2认同)

Tem*_*Rex 27

对于像空的定义,不可能区分语义的差异

class C {
public:

};
Run Code Online (Sandbox Code Playgroud)

struct S {

};
Run Code Online (Sandbox Code Playgroud)

或类似的

class C {

};
Run Code Online (Sandbox Code Playgroud)

struct S {
private:

};
Run Code Online (Sandbox Code Playgroud)

structvs class关键字外,没有可检测到的行为差异.另见此问答.

:由于通过说过@KyleStrand,推导也需要明确的访问说明,所以S : private Base {};C : Base {};是等价的,同为S : Base {};C : public Base {};,其中S是一个结构,C是一类,并且Base可以是.

  • 你可能应该添加一些东西来指示(根据你引用的答案)对于完整的struct/class语义相等,基类访问说明符也必须是显式的,例如`struct Derived:Base {`相当于`class Derived: public Base {public:`和`class Derived:Base {`相当于`struct Derived:private Base {private:`. (3认同)

Rob*_*b K 24

他们是一回事.唯一的区别(默认成员可见性)仅在编译时存在.否则在struct和之间没有任何区别class.

ETA:你可能想要的是std::is_pod,它将告诉你你的班级是否是"普通旧数据类型".关于这个问题的大部分讨论和评论似乎表明,这就是那些认为应该有区别的人真正想要的.

  • 就C ++语言和关键字而言,它们是相同的。但是有趣的是,`struct`更常用于简单的POD类,而在自然语言中,单词“ struct [ure]”更常用于POD或标准布局类。因此,有些人可能会*直观地做出区分。您还问过“区分它们的重点是什么?”。*答案:一个人可能想告诉其他人C兼容的聚合(请参阅我对OP的回答)。语言*可以*选择使用关键字`struct`和`class`来实现这种区分,但事实并非如此。 (2认同)

Pet*_*ica 15

也有人指出正确的,在C++中的关键字struct,并class具有除了在会员能见度差的含义相同.

您是否调用聚合类型,因此定义"结构"或"类"或"weiruewzewiruz"取决于您.为了沟通,通常建议遵循既定的惯例,因此我建议反对"weiruewzewiruz".

还建议使用语义差异作为单词选择的指导.对于struct没有大量内部逻辑和不变量的简单聚合数据,使用更为常见; 一个典型的用途是struct point { float x; float y; };.这些类型在文献中通常称为"结构"或"结构".如果有人fprintf在C++中使用将第一个参数称为"指向FILE结构的指针" ,那就不足为奇了.FILE是Scott Meyers在"更有效的C++"中的含义的一个例子,第34项:

可以安全地假设两种语言编译的结构定义[C和C++ -pas]由两个编译器以相同的方式排列.

关于自然语言,单词选择"结构"并非巧合:迈耶斯正在谈论一种普通的旧数据集合,它在两种语言中具有相同的语义,直到位级别.

关于编程语言,如果所讨论的数据聚合的C++定义使用了关键字structclass(使用公共访问说明符),则无关紧要.struct也许是更自然的选择,因为聚合的C++语义是C结构的语义.此外,使用structC和C++源可以更轻松地共享一个类型定义.

C++标准在自然语言和编程语言中使用"struct"和"structure",不仅在互操作性的情况下:1.7/5:"结构声明为",或3.2/4 struct X; // declare X as a struct type.最有趣的是9/8,为互操作标准奠定了基础:

标准布局结构是使用类键结构或类键类定义的标准布局类.[...]

任何阅读此内容的人都可以声称C++中没有任何结构是超出我的.这显然不是编辑错误,因为术语"struct"和"class"是相互明确设置的.


然而,比单词选择和品味问题更有趣的是明显的,可测试的差异.在什么情况下C++聚合与C相当并且兼容struct?也许这个问题是你的问题的根源?报价中提到的标准布局是标准.它在9/7中详细说明,并且基本上规定了这一点

  • 继承层次结构中只有一个类可能具有非静态数据成员定义(可能是因为标准不希望指定在这种层次结构中的不同级别定义的数据元素的顺序);
  • 不允许使用虚函数或虚基类(因为运行时信息需要额外的实例数据);
  • 所有成员都具有相同的"访问控制"(公共,受保护或私有;可能因为访问控制可以免费订购实现).

然后标准说

9 [注意:标准布局类对于与使用其他编程语言编写的代码进行通信非常有用.它们的布局在9.2中指定.-尾注]

当然,在C中编译的结构定义符合这些标准,因此Scott Meyers的断言.FILE来自stdio.h是一个突出的,不是非常重要的例子.请注意,标准不保证,因为对象布局是依赖于实现的,并且可能仅使用编译器选项进行更改.

是否具有标准布局的类可以使用类型特征进行测试std::is_standard_layout<T>.以下程序受到cppreference示例的启发,检查标准中列出的主要案例.

#include <cstdio>
#include <typeinfo>
#include <type_traits>

using namespace std;

struct funcOnlyT // fine
{
    int f();
};

class podT {   // "class" is ok
    int m1;
    int m2;
};

struct badAccessCtrlT { // bad: public/private
    int m1;
private:
    int m2;
};

struct polymorphicT {  // bad: polymorphic
    int m1;
    int m2;
    virtual void foo();
};


struct inheritOkT: podT // ok: inheritance, data only on one level
{
    int f();
};


struct inheritPlusDataT: podT // bad: inheritance, data on 2 levels
{
    int m3;
};

template<typename T1, typename T2>
struct templT     // ok with std layout types T1, T2
{
    T1 m1;
    T2 m2;
};

// print type "name" and whether it's std layout
template<typename T>
void printIsStdLayout()
{
    printf("%-20s: %s\n", 
            typeid(T).name(),
            std::is_standard_layout<T>::value 
                ? "is std layout" 
                : "is NOT std layout");
}

int main()
{
    printIsStdLayout<funcOnlyT>();
    printIsStdLayout<podT>();
    printIsStdLayout<badAccessCtrlT>();
    printIsStdLayout<polymorphicT>();
    printIsStdLayout<inheritOkT>();
    printIsStdLayout<inheritPlusDataT>();
    printIsStdLayout<templT<int, float> >();
    printIsStdLayout<FILE>();
}
Run Code Online (Sandbox Code Playgroud)

示例会话:

$ g++ -std=c++11 -Wall -o isstdlayout isstdlayout.cpp && ./isstdlayout
9funcOnlyT          : is std layout
4podT               : is std layout
14badAccessCtrlT    : is NOT std layout
12polymorphicT      : is NOT std layout
10inheritOkT        : is std layout
16inheritPlusDataT  : is NOT std layout
6templTIifE         : is std layout
9__sFILE64          : is std layout
Run Code Online (Sandbox Code Playgroud)

  • 从您引用的散文的标准角度来看,我愿意妥协并接受C ++可能会有“结构”的概念,而“结构”是“类”的子集。但是,在您引述为9/8的那一段话中,这并不等同于“人们可以使用关键字`struct`定义的一组类型”。我会进一步说,这些所谓的“结构”的标准意义既未被广泛认可,也不足以使特征类型以其命名。 (2认同)
  • @LightnessRacesinOrbit ...任何历史原理,如果有相关的话,都是C++中*结构的参数*,而不是它们.因此,你拒绝接受评论中提出的所有实质性论据和证据,并且只有在我写完一份精心准备,详细,证据证据的逐步反驳后,你才会说半年之后你会"愿意"妥协".我认为有限的洞察力可能更早出现. (2认同)

Che*_*Alf 7

C++11§9/ 8 ([class]/8):

"标准布局结构是与定义的标准布局类类键 struct类键 class.甲标准布局联盟是与定义的标准布局类类键 union.

C++11§9/ 10 ([class]/10):

"POD结构是一种非联合类既是琐碎类和一个标准布局类,和具有类型的非POD结构,非POD联合(或这些类型的阵列)的无非静态数据成员.[...]

由于POD结构是标准布局类,因此它是标准布局结构的子集.据我所知,这是C++标准中struct的最一般含义.所以你想要的是一个类型特征或一组类型特征,它们可以让你识别标准布局结构.

瞧,看着类型列表性状有is_classis_standard_layout.当一种类型令人满意时,它就是一个"结构".或者更确切地说,它是标准布局结构,由C++11§9/ 8定义.


关于

"我想知道为什么类型特征中的[class和struct]之间没有区别

好吧,有.这是is_standard_layout特质.


关于

"检查这种差异总是没用,还是有一些我不理解的理由?

不,检查这种差异并非毫无用处.该标准定义了标准布局,因为它非常实用.正如标准本身所说,

C++11§9/ 9 ([class]/9):

" [注意:标准布局类对于与用其他编程语言编写的代码进行通信非常有用.它们的布局在9.2中指定.-尾注]


注意:
¹该is_class特征对于a classstruct,但不适用于a union,即使标准定义"联合是一个类".即特征比一般术语更具体.

  • 虽然你对标准的"POD结构"定义提出了一个公平而有趣的观点(我认为这是一个继承自历史的编辑问题,但我不打算在此论证),我认为这是一个合理的假设. OP正在谈论关键字`class` vs`struct`.因此,我建议在你的答案中添加一个注释,即"struct"的定义不是OP所指的那个(也许). (2认同)