Я хочу определить во время компиляции (статическое утверждение), соответствует ли класс обоим следующим условиям:
Идея состоит в том, чтобы избежать работы с объектами с неинициализированными членами. Я знаю, что есть разные способы сделать это во время кодирования, но я также хочу, чтобы механизм обнаруживал это во время компиляции. Я пытался использовать различные функции 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
Вы, вероятно, захотите сделать это с помощью статического анализатора, инструмент clang может помочь.
@MaximEgorushkin только из имени типа? Теперь мне любопытно.
@Timo Можно перебирать члены класса, поддерживающего агрегатную инициализацию, с помощью github.com/аполухин/magic_get . К сожалению, это задыхается от std::string
участников. В противном случае было бы почти тривиально перебрать все элементы и определить, является ли какой-либо из них POD.
@MaximEgorushkin вау, это гениально. Я понял идею этого, но я не понимаю, как работает подсчет участников. И как можно выполнить агрегированную инициализацию (для получения типов членов) без необходимости явно записывать ее для каждого возможного количества членов (например, T{m1, m2, m3}
, mX
являются детекторами)?
@Timo Смотрите выступление автора с полной информацией: Better C++14 Reflections - Антоний Полухин - Встреча с C++ 2018.
Во-первых, мне кажется неправильным ожидать от пользователя класса заботы об инициализации его члена. Вы должны убедиться, что все его члены инициализированы в самом классе, а не где-то еще, где он используется.
То, что вы ищете, не существует, а если бы и существовало, оно бы вам даже не помогло. Наличие явного конструктора не гарантирует, что элемент данных будет инициализирован. С другой стороны, в C++11 можно даже инициализировать элементы данных без явного написания конструктора (используя синтаксис фигурных скобок в объявлении класса). Кроме того, вы, похоже, просто заботитесь о неинициализированных членах POD, но как насчет неинициализированных членов, не являющихся POD?
Тем не менее, компилятор может генерировать предупреждения о неинициализированных значениях, но часто вам нужно включить это предупреждение (например, параметр -Wuninitialized для gcc). Большинство компиляторов позволяют принудительно обрабатывать предупреждения как ошибки. В сочетании это может дать вам желаемый эффект даже без специального написания кода для его проверки, и это также будет работать для любых неинициализированных значений, а не только в классах. Возможно, это решение, которое вы ищете.
-Wuninitialized
входит в -Wall
. Всегда нужно начинать с -Wall -Wextra -Werror
. +1
Используя -Wuninitialized, я не получаю предупреждений для классов без конструктора, у которых есть члены POD, и не получаю предупреждений для конструкторов, которые не инициализируют некоторые из своих членов POD. Кроме того, в среде IDE, с которой я работаю (eclipse), есть предупреждения о конструкторах, которые не инициализируют членов POD, но нет предупреждений о классах без конструкторов. Есть идеи?
@EranBentov gcc 5.4.0 выдает мне предупреждения для неинициализированных членов классов POD. Обратите внимание, что это предупреждение выдается при использовании члена, а не тогда, когда конструктор его не инициализирует. Нет требования, чтобы конструктор инициализировал все свои члены. Какой компилятор и версию вы используете?
Я использую gcc 4.8.5
@EranBentov, довольно старый, с 2015 года. Я бы рекомендовал использовать более новый gcc. Даже мой 5.4.0 очень старый, но, к сожалению, я пока застрял с ним. Самая последняя версия — gcc 9.1. Много улучшений в предупреждениях и сообщениях об ошибках, многое стало намного проще!
Вы не можете автоматически определять члены типа (т. е. вы не можете перебирать члены типа). Также вы можете использовать агрегатную инициализацию для полной инициализации типов, содержащих неинициализированные модули.