Почему нет признака типа std::is_struct?

Я видел это для того, чтобы проверить, если тип T это класс, который я могу использовать:

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

Возвращает true как для классов, так и для структур. Я знаю, что в C++ это почти одно и то же, но я хотел бы знать, почему нет различия между ними в типе черты. Всегда ли бесполезно проверять эту разницу или есть еще одна причина, которую я не понимаю?

5 ответов

Решение

Возвращает true как для классов, так и для структур. Я знаю, что в C++ это почти одно и то же, но я хотел бы знать, почему нет различия между ними в типе черты.

К сожалению, это распространенное заблуждение в C++. Иногда это происходит из-за фундаментального недопонимания, но иногда это происходит из-за двусмысленности в английском языке. Это может быть из-за неточной диагностики компилятора, плохо написанных книг, неправильных ответов SO…

Вы, наверное, читали что-то вроде этого:

"В C++ нет разницы между структурой и классом, кроме стандартной видимости членов и баз".

Этот отрывок может быть истолкован в некотором смысле, что вводит в заблуждение, потому что понятия идентичности и равенства трудно различить при использовании фраз типа "без разницы".

На самом деле, C++ не имеет структур с 1985 года. Он имеет только классы.

Типы типов, которые вы объявляете с помощью ключевого слова class и ключевое слово struct это классы. Период. Ключевое слово structи правила видимости, которые используются по умолчанию при определении класса с использованием этого ключевого слова, были сохранены только для обратной совместимости с C … но это синтаксис. Это не делает результирующие типы на самом деле другого типа.

Черта типа не делает различий, потому что буквально не один, чтобы сделать.

Невозможно различить разницу в семантике для пустых определений, таких как

class C {
public:

};

от

struct S {

};

или аналогично

class C {

};

а также

struct S {
private:

};

Отдельно от struct против class Ключевое слово, поведенческих различий не обнаружено. Смотрите также этот Q & A.

Примечание. Как отмечает @KyleStrand, для деривации также необходимы явные спецификаторы доступа, поэтому S : private Base {}; а также C : Base {}; эквивалентны, так же, как S : Base {}; а также C : public Base {};, где S это структура, C это класс, и Base может быть.

Это одно и то же. Единственная разница (видимость элемента по умолчанию) существует только во время компиляции. В противном случае нет никакой разницы между struct а также class,

ETA: То, что вы, вероятно, хотите std::is_pod, который скажет вам, является ли ваш класс "простым старым типом данных". Большая часть обсуждения и комментариев по этому вопросу, кажется, указывает на то, что именно этого действительно хотят те, кто считает, что должно быть различие.

Другие правильно указали, что в C++ ключевые слова struct а также class имеют то же значение, за исключением разницы в видимости членов.

Называете ли вы агрегатные типы, определенные таким образом, "структурами" или "классами" или "weiruewzewiruz" - решать вам. В интересах общения, как правило, рекомендуется следовать установленным конвенциям, поэтому я бы посоветовал против "weiruewzewiruz".

Также рекомендуется использовать семантические различия в качестве ориентира для выбора слов. Использование struct более распространен для простых агрегированных данных, которые не имеют много внутренней логики и инвариантов; типичное использование будет struct point { float x; float y; };, Такие типы часто называют "структурами" или "структурами" в литературе. Не удивительно, если кто-то использует fprintf в C++ первый аргумент упоминается как "указатель на структуру FILE". FILE является примером того, что Скотт Мейерс имеет в виду в "Более эффективном C++", пункт 34:

Можно с уверенностью предположить, что определение структуры, которое компилируется в обоих языках [C и C++ -pas], выстроено одинаково обоими компиляторами.

Что касается естественного языка, то выбор слова "структура" не случаен: Мейерс говорит о простой старой совокупности данных, которая имеет одинаковую семантику в обоих языках, вплоть до уровня битов.

Что касается языка программирования, не имеет значения, будет ли ключевое слово C++ для рассматриваемого агрегата данных использовать ключевое слово struct или же class (со спецификатором публичного доступа). 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 Структура стандартного макета - это класс стандартного макета, определенный структурой ключ-класс или класс-ключ. [...]

То, как кто-то, читающий это, может утверждать, что в C++ нет структур, мне не под силу. Это явно не ошибка редактирования, потому что термины "структура" и "класс" явно установлены по отношению друг к другу.


Однако более интересными, чем выбор слов и вопросы вкуса, являются очевидные, проверяемые различия. При каких обстоятельствах агрегат C++ сопоставим и совместим с C struct? Возможно, этот вопрос лежал в основе вашего вопроса? Стандартное расположение, указанное в цитате, является критерием. Это подробно описано в 9/7 и по существу предписывает, что

  • только один класс в иерархии наследования может иметь нестатические определения элементов данных (возможно, потому, что стандарт не хочет указывать порядок элементов данных, определенных на разных уровнях в такой иерархии);
  • запрещены виртуальные функции или виртуальные базовые классы (из-за дополнительных данных экземпляров, необходимых для информации времени выполнения);
  • все члены имеют одинаковый "контроль доступа" (общедоступный, защищенный или частный; возможно, потому что реализация свободна для заказа с помощью контроля доступа).

Стандарт тогда говорит

9 [Примечание: классы стандартной компоновки полезны для связи с кодом, написанным на других языках программирования. Их расположение указано в 9.2. - конец примечания]

Конечно, определение структуры, которое компилируется в C, удовлетворяет этим критериям, отсюда и утверждение Скотта Мейерса. 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>();
}

Пример сеанса:

$ 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
C++ 11 §9 / 8 ([класс] / 8):

Структура стандартного макета - это класс стандартного макета, определенный с помощью ключа класса struct или ключ класса class, Объединение стандартного макета - это класс стандартного макета, определенный с помощью ключа класса union,

C++ 11 §9 / 10 ([класс] / 10):

" Структура POD - это класс, не являющийся объединением, который является как тривиальным классом, так и классом стандартной компоновки и не имеет нестатических членов-данных типа не-POD-структуры, не-POD-объединения (или массива таких типов). [...]

Поскольку структура POD является классом стандартной компоновки, она является подмножеством структуры стандартной компоновки. Насколько я знаю, это самое общее значение struct в стандарте C++. И поэтому, вероятно, вы ищете черту типа или набор черт типа, который позволяет вам идентифицировать структуру стандартного макета как таковую.

И вуаля, глядя на список типов черт есть is_class а также is_standard_layout, Когда тип удовлетворяет обоим, это "структура". Или, точнее, это структура стандартного макета, как определено в C++11 §9/8.


относительно

" Я хотел бы знать, почему нет различия между [классом и структурой] в признаке типа

Ну, есть. Это is_standard_layout черта характера.


относительно

Всегда ли бесполезно проверять эту разницу или есть еще одна причина, которую я не понимаю?

Нет, это бесполезно, чтобы проверить эту разницу. Стандарт определяет макет стандарта по той причине, что он практически полезен. Как отмечает сам стандарт,

C++ 11 §9 / 9 ([класс] / 9):

[Примечание: Стандартные классы макета полезны для связи с кодом, написанным на других языках программирования. Их расположение указано в 9.2. - конец примечания]


Заметки:
¹ is_class черта верна для class или же struct , но не для union даже если стандарт определяет, что "объединение есть класс". Т.е. черта более конкретна, чем общая терминология.

Другие вопросы по тегам