Почему нет черты 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
, хотя стандарт определяет, что "объединение - это класс". То есть черта более специфична, чем общая терминология.