Почему нет признака типа 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 / 10 ([класс] / 10):Структура стандартного макета - это класс стандартного макета, определенный с помощью ключа класса
struct
или ключ классаclass
, Объединение стандартного макета - это класс стандартного макета, определенный с помощью ключа классаunion
,
" Структура 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
даже если стандарт определяет, что "объединение есть класс". Т.е. черта более конкретна, чем общая терминология.