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

时间:2015-09-22 14:40:25

标签: c++ c++11 typetraits

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

bool isClass = std::is_class<T>::value;

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

5 个答案:

答案 0 :(得分:165)

  

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

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

你可能读过这样的东西:

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

这段经文可以被误解,因为当使用“无差异”这样的短语时,身份平等的概念很难区分。< / p>

事实上,自1985年以来,C ++一直没有结构。它只有类。

The kind of types that you declare with the keyword class and the keyword struct are classes。期。关键字struct以及使用该关键字定义类时默认的可见性规则仅用于向后兼容C ...但这是语法问题。它不会使结果类型实际上属于不同类型。

类型特征没有区别,因为实际上不是一个可以制作的。

答案 1 :(得分:26)

无法区分像

这样的空定义的语义差异
class C {
public:

};

struct S {

};

或类似地

class C {

};

struct S {
private:

};

struct vs class关键字外,没有可检测到的行为差异。另请参阅this Q&A

注意:正如@KyleStrand所述,派生还需要显式访问说明符,因此S : private Base {};C : Base {};是等价的,与S : Base {};和{相同{1}},其中C : public Base {};是结构,S是一个类,C可以是。

答案 2 :(得分:23)

他们是同一件事。唯一的区别(默认成员可见性)仅在编译时存在。在structclass之间没有任何区别。

ETA:您可能想要的是std::is_pod,它会告诉您您的班级是否是一个普通的旧数据类型&#34;。关于这个问题的大部分讨论和评论似乎都表明,这就是那些认为应该有区别的人。

答案 3 :(得分:14)

其他人已经正确地指出,在C ++中,关键字structclass具有相同的含义,除了成员可见性的差异。

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

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

  

可以安全地假设编译在两者中的结构定义   语言[C和C ++ -p.a.s]由两个编译器以相同的方式布局。

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

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

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

  

8标准布局结构是标准布局类   使用class-key结构或类键定义   类。 [...]

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

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

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

标准然后说

  

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

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

是否可以使用特征类型std::is_standard_layout<T>测试类是否具有标准布局。以下程序受an example on 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>();
}

示例会话:

$ 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

答案 4 :(得分:7)

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

标准布局结构是使用 class-key struct或<定义的标准布局类em> class-key class标准布局联合是使用 class-key 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_classclass的{​​{1}}特征是真的,但struct的特征是真的,即使标准定义“联合是一个类”。即特征比一般术语更具体。 功能