Почему нет черты std:: is_struct?

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

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

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

Ответы

Ответ 1

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

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

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

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

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

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

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

Типичная черта не делает различий, потому что буквально это не так.

Ответ 2

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

class C {
public:

};

от

struct S {

};

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

class C {

};

и

struct S {
private:

};

Помимо ключевого слова struct vs class, поведенческая разница не обнаруживается. См. Также этот Q & A.

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

Ответ 3

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

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

Ответ 4

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

Если вы вызываете агрегированные типы, определенные таким образом, "structs" или "classes" или "weiruewzewiruz" зависит от вас. В интересах общения, как правило, рекомендуется придерживаться установленных конвенций, поэтому я бы посоветовал "weiruewzewiruz".

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

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

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

Что касается языка программирования, не имеет значения, использовало ли в С++ определение совокупности данных ключевое слово struct или class (с указателем общего доступа). struct, пожалуй, более естественный выбор, потому что семантика С++ совокупности является семантикой структуры C. Кроме того, использование struct позволяет как источникам C, так и С++ упростить совместное использование одного определения типа.

Стандарт С++ использует "структуру" и "структуру" как на естественном, так и на языке программирования не только в случаях совместимости: 1.7/5: "Структура, объявленная как", или 3.2/4 struct X; // declare X as a struct type. Наиболее интересным является 9/8, укладывая почву для межочередных критериев:

8 Структура стандартного макета - класс стандартного макета определенные с помощью структуры класса или ключа класса класс. [...]

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


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

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

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

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

Конечно, определение структуры, которое компилируется в 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 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

Ответ 5

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

" Структура стандартного макета - это класс стандартного макета, определенный с помощью ключа класса struct или класса-ключа class. Стандартно-макетный союз является стандартным макетом класс, определенный с помощью ключа класса union.

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

" Структура POD - это неединичный класс, который является тривиальным классом и классом стандартного макета, и не имеет нестатические члены данных типа non-POD struct, non-POD union (или массив таких типов). [& Hellip;]

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

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


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

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

Ну, есть. Это признак is_standard_layout.


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

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

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

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

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


Примечания:
¹ Значение is_class истинно для class или struct, но не для a union, хотя стандарт определяет, что "объединение - это класс". То есть черта более специфична, чем общая терминология.