Как я могу определить, имеет ли класс неявный конструктор и примитивные члены в С++?

Я хочу определить во время компиляции (статическое утверждение), соответствует ли класс обоим следующим условиям:

  • Имеет неявный конструктор по умолчанию (т. е. без определяемого пользователем конструктора по умолчанию).
  • Имеет по крайней мере один элемент данных, который является подом (т. е. элемент, чья инициализация по умолчанию предполагает, что любые случайные байты были в его адресе памяти). [Надеюсь, я правильно употребил здесь термин pod]

Идея состоит в том, чтобы избежать работы с объектами с неинициализированными членами. Я знаю, что есть разные способы сделать это во время кодирования, но я также хочу, чтобы механизм обнаруживал это во время компиляции. Я пытался использовать различные функции std/boost, такие как is_tribuly_constructible, is_pod, но ни одна из них не дает точных условий, которые мне нужны.

Например, допустим, у меня есть следующие классы:

struct A
{
  int a;
}

struct B
{
  int* b;
}

struct C
{
  bool c;
  std::string c_str_; 
}

struct D
{
  D();
  float d; 
}

struct E
{
  std::string e;
}

Предполагая, что нужная мне функция называется «has_primitive_and_implicit_ctor», я бы хотел, чтобы вывод для каждого вызова был таким, как в комментариях:

has_primitive_and_implicit_ctor<A>(); //true - A has at least one pod type member (int)
has_primitive_and_implicit_ctor<B>(); //true - A has at least one pod type member (pointer)
has_primitive_and_implicit_ctor<C>(); //true - A has at least one pod type member (bool), even though there is one non-pod member
has_primitive_and_implicit_ctor<D>(); //false - has a pod member(float), but a user defined ctor
has_primitive_and_implicit_ctor<E>(); //false - doesn't have a default ctor but has no pod members

Вы не можете автоматически определять члены типа (т. е. вы не можете перебирать члены типа). Также вы можете использовать агрегатную инициализацию для полной инициализации типов, содержащих неинициализированные модули.

Timo 26.06.2019 16:19

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

Jarod42 26.06.2019 16:36

@MaximEgorushkin только из имени типа? Теперь мне любопытно.

Timo 26.06.2019 16:40

@Timo Можно перебирать члены класса, поддерживающего агрегатную инициализацию, с помощью github.com/аполухин/magic_get . К сожалению, это задыхается от std::string участников. В противном случае было бы почти тривиально перебрать все элементы и определить, является ли какой-либо из них POD.

Maxim Egorushkin 26.06.2019 17:25

@MaximEgorushkin вау, это гениально. Я понял идею этого, но я не понимаю, как работает подсчет участников. И как можно выполнить агрегированную инициализацию (для получения типов членов) без необходимости явно записывать ее для каждого возможного количества членов (например, T{m1, m2, m3}, mX являются детекторами)?

Timo 26.06.2019 19:19

@Timo Смотрите выступление автора с полной информацией: Better C++14 Reflections - Антоний Полухин - Встреча с C++ 2018.

Maxim Egorushkin 26.06.2019 19:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
179
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

То, что вы ищете, не существует, а если бы и существовало, оно бы вам даже не помогло. Наличие явного конструктора не гарантирует, что элемент данных будет инициализирован. С другой стороны, в C++11 можно даже инициализировать элементы данных без явного написания конструктора (используя синтаксис фигурных скобок в объявлении класса). Кроме того, вы, похоже, просто заботитесь о неинициализированных членах POD, но как насчет неинициализированных членов, не являющихся POD?

Тем не менее, компилятор может генерировать предупреждения о неинициализированных значениях, но часто вам нужно включить это предупреждение (например, параметр -Wuninitialized для gcc). Большинство компиляторов позволяют принудительно обрабатывать предупреждения как ошибки. В сочетании это может дать вам желаемый эффект даже без специального написания кода для его проверки, и это также будет работать для любых неинициализированных значений, а не только в классах. Возможно, это решение, которое вы ищете.

-Wuninitialized входит в -Wall. Всегда нужно начинать с -Wall -Wextra -Werror. +1
Maxim Egorushkin 27.06.2019 11:22

Используя -Wuninitialized, я не получаю предупреждений для классов без конструктора, у которых есть члены POD, и не получаю предупреждений для конструкторов, которые не инициализируют некоторые из своих членов POD. Кроме того, в среде IDE, с которой я работаю (eclipse), есть предупреждения о конструкторах, которые не инициализируют членов POD, но нет предупреждений о классах без конструкторов. Есть идеи?

Eran Bentov 30.06.2019 09:52

@EranBentov gcc 5.4.0 выдает мне предупреждения для неинициализированных членов классов POD. Обратите внимание, что это предупреждение выдается при использовании члена, а не тогда, когда конструктор его не инициализирует. Нет требования, чтобы конструктор инициализировал все свои члены. Какой компилятор и версию вы используете?

Martin Hierholzer 01.07.2019 10:14

Я использую gcc 4.8.5

Eran Bentov 03.07.2019 13:34

@EranBentov, довольно старый, с 2015 года. Я бы рекомендовал использовать более новый gcc. Даже мой 5.4.0 очень старый, но, к сожалению, я пока застрял с ним. Самая последняя версия — gcc 9.1. Много улучшений в предупреждениях и сообщениях об ошибках, многое стало намного проще!

Martin Hierholzer 04.07.2019 14:06

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