Рассматривать:
struct Person
{
int height;
int weight;
int age;
};
int main()
{
Person p { .age = 18 };
}
Приведенный выше код допустим для C99, но не для C ++ 11.
Что это было C ++ 11 обоснование стандартного комитета для исключения поддержки такой удобной функции?
OVERLAPPED
является таким примером. Возможность писать={.Offset=12345};
сделает код более понятным (и, вероятно, менее подверженным ошибкам). Сокеты BSD - аналогичный пример.main
C99. Следует читатьstruct Person p = { .age = 18 };
Ответы:
В C ++ есть конструкторы. Если имеет смысл инициализировать только один член, это можно выразить в программе, реализовав соответствующий конструктор. Это своего рода абстракция, которую продвигает C ++.
С другой стороны, функция назначенных инициализаторов больше предназначена для раскрытия и упрощения доступа к членам непосредственно в клиентском коде. Это приводит к таким вещам, как наличие человека 18 (лет?), Но с нулевым ростом и весом.
Другими словами, назначенные инициализаторы поддерживают стиль программирования, в котором раскрываются внутренние компоненты, а клиенту предоставляется гибкость в выборе способа использования этого типа.
C ++ больше заинтересован в предоставлении гибкости разработчику типа, чтобы дизайнеры могли упростить правильное использование типа и упростить использование некорректно. Часть этого заключается в том, чтобы дать дизайнеру контроль над тем, как можно инициализировать тип: дизайнер определяет конструкторы, инициализаторы класса и т. Д.
источник
Person
чтобы его автор хотел предоставить пользователям максимально возможную гибкость для установки и инициализации членов? Пользователь тоже уже может писатьPerson p = { 0, 0, 18 };
(и на то есть веские причины).Person
имеет дизайн в стиле C, поэтому функции C могут иметь смысл. Однако C ++, вероятно, позволяет улучшить дизайн, который также устраняет необходимость в назначенных инициализаторах. - На мой взгляд, снятие ограничения на классовые инициализаторы для агрегатов гораздо больше соответствует духу C ++, чем назначенные инициализаторы.15 июля '17 P0329R4 принят вC ++ 20стандарт: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0329r4.pdf
Это обеспечивает ограниченную поддержкуc99Назначенные инициализаторы. Это ограничение описано ниже в C.1.7 [diff.decl] .4, учитывая:
Следующие назначенные инициализации, допустимые в C, ограничены в C ++:
struct A a = { .y = 1, .x = 2 }
недопустим в C ++, потому что указатели должны появляться в порядке объявления элементов данныхint arr[3] = { [1] = 5 }
недействителен в C ++, потому что инициализация массива не поддерживаетсяstruct B b = {.a.x = 0}
недопустимо в C ++, потому что указатели не могут быть вложеннымиstruct A c = {.x = 1, 2}
недопустимо в C ++, потому что все или ни один из элементов данных должен быть инициализирован указателямиДля C ++ 17и более ранние версии Boost фактически поддерживают назначенные инициализаторы, и было множество предложений по добавлению поддержки дляC ++стандарт, например: n4172 и предложение Дэрила Уолкера о добавлении обозначения к инициализаторам . В предложениях говорится о реализацииc99Назначенные инициализаторы в Visual C ++, gcc и Clang утверждают:
Но комитет по стандартизации неоднократно отклоняет такие предложения , заявляя:
Комментарии Бена Фойгта помогли мне увидеть непреодолимые проблемы с этим подходом; дано:
В каком порядке будут вызываться эти функции в c99:
struct X foo = {.a = (char)f(), .b = g(), .c = h()}
? Удивительно, но вc99:(Visual C ++, gcc и Clang, похоже, имеют согласованное поведение, поскольку все они будут выполнять вызовы в этом порядке :)
h()
f()
g()
Но неопределенная природа стандарта означает, что если бы эти функции взаимодействовали, результирующее состояние программы также было бы неопределенным, и компилятор не предупредил бы вас : есть ли способ получить предупреждение о неправильном поведении назначенных инициализаторов?C ++ действительно имеет жесткие требования к инициализатору-лист 11.6.4 [dcl.init.list] 4:
Так C ++ служба поддержки потребовала бы, чтобы это было выполнено в следующем порядке:
f()
g()
h()
Нарушение совместимости с предыдущими c99Реализации.
Как обсуждалось выше, эту проблему удалось обойти за счет ограничений на назначенные инициализаторы, принятые вC ++ 20, Они обеспечивают стандартизованное поведение, гарантируя порядок выполнения назначенных инициализаторов.
источник
struct X { int c; char a; float b; }; X x = { .a = f(), .b = g(), .c = h() };
вызовh()
выполняется доf()
илиg()
. Если определенияstruct X
нет рядом, это будет очень удивительно. Помните, что выражения инициализатора не обязательно должны быть свободными от побочных эффектов.Немного хакерства, так что просто поделитесь ради удовольствия.
И используйте это так:
который расширяется до:
источник
$
типаT
, и вы назначаете ее члены непосредственно перед ее возвратом. Острота. Интересно, есть ли проблемы с производительностью.Назначенные инициализаторы в настоящее время включены в объем работ по C ++ 20: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0329r4.pdf, чтобы мы наконец могли их увидеть!
источник
&
оператор вернет адрес, который объект будет иметь в течение своего времени жизни).Две основные функции C99, которые отсутствуют в C ++ 11, упоминаются как «Назначенные инициализаторы и C ++».
Я думаю, что «назначенный инициализатор» связан с потенциальной оптимизацией. Здесь в качестве примера я использую «gcc / g ++» 5.1.
Мы знали во время компиляции, что он
a_point.x
равен нулю, поэтому мы могли ожидать, что онfoo
будет оптимизирован в одинprintf
.foo
оптимизированx == 0
только для печати .Для версии C ++
И это результат оптимизированного ассемблерного кода.
Мы видим, что на
a_point
самом деле это не постоянная времени компиляции.источник
constexpr point(int _x,int _y):x(_x),y(_y){}
. Оптимизатор clang ++, похоже, также устраняет сравнение в вашем коде. Итак, это просто проблема QoI.struct addrinfo
илиstruct sockaddr_in
, поэтому вам остаются присваивания отдельно от объявлений.