Условный тернарный оператор
Тернарный оператор ?: позволяет сократить определение простейших условных конструкций if и имеет следующую форму:
Оператор ?: предоставляет сокращенный способ (альтернативу) ветвления if/else.
Стейтменты if/else:
if (condition)
expression;
else
other_expression;
можно записать как:
(condition) ? expression : other_expression;
Обратите внимание, операнды условного оператора должны быть выражениями (не стейтментами).
Например, ветвление if/else, которое выглядит следующим образом:
if (condition)
x = some_value
else
x = some_other_value
можно записать как:
x = (condition) ? some_value : some_other_value;
Большинство предпочитает последний вариант из-за лучшей читабельности.
Другой пример: чтобы разместить значение х или у в переменной larger мы можем сделать так:
if (x > y)
larger = x;
else
larger = y;
или вот так:
larger = (x > y) ? x : y;
Обычно часть с условием помещают внутри скобок, чтобы убедиться, что приоритет сохранен правильно. Также так удобнее читать. Выражения между ? и : вычисляются так, как если бы они находились в круглых скобках. Помните, оператор ?: имеет очень низкий приоритет. Если делать что-либо другое, кроме операции присваивания, то стейтмент с оператором ?: нужно записывать внутри круглых скобок. Например, для вывода х и у, мы можем сделать следующее:
if (x > y)
cout << x;
else
cout << y;
Или вот это:
cout << ((x > y) ? x : y);
1
cout << ((x > y) ? x : y);
Поскольку оператор << имеет более высокий приоритет, чем ?:, то стейтмент:
cout << (x > y) ? x : y;
1
cout << (x > y) ? x : y;
будет вычисляться как:
(cout << (x > y)) ? x : y;
1
(cout << (x > y)) ? x : y;
В консольном окне мы увидим 1 (true), если х > у или 0 (false), если x < y.
Условный оператор – это удобный способ упростить ветвление if/else, особенно при присваивании результата переменной или возврате значения, как части возврата функции. Но его не следует использовать вместо сложных ветвлений if/else, так как в таких случаях читабельность кода резко ухудшается и вероятность ошибок выше.
Условный оператор вычисляется как выражение
Стоит отметить, что условный оператор вычисляется как выражение, в то время как ветвление if/else, как стейтменты. Это означает, что ?: может быть использован там, где if/else нет.
Например, при инициализации константы:
bool inBigClassroom = false;
const int classSize = inBigClassroom ? 30 : 20;
Здесь нельзя использовать if/else, так как константы должны быть инициализированы при объявлении, а стейтмент не может быть значением для инициализации.
Секреты тернарного оператора
Тернарный оператор выделяется из ряда других операторов в С++. Его называют "conditional expression". Ну а так как это expression, выражение, то как у каждого выражения, у него должен быть тип и value category.
Здесь начинается самое интересное. Оказывается типом тернарного оператора будет наиболее общий тип его двух последних операндов. Что значит наиболее общий? Это легче всего пояснить на примерах. У int и short общим типом будет int. У A и B в следующем фрагменте общим типом будет также int
struct A{ operator int(){ return 1; } };
struct B{ operator int(){ return 3; } };
Т.е. наиболее общий тип это такой тип, к которому могу быть приведены оба операнда. Вполне могут быть ситуации, когда общего типа нет. Например у
struct C{};
struct D{};
общего типа нет, и следующий фрагмент вообще не скомпилируется
(true ? C() : D());
С типом тернарного оператора мы немного разобрались. Осталось решить вопрос с value category. Тут действует следующее правило: если в тернарном операторе происходит преобразование типов к наиболее общему, то тернарный оператор — rvalue. Если же нет, то lvalue.
sizeof
Синтаксис
sizeof unary-expression
sizeof ( type-name )
Результат оператора sizeof имеет тип size_t, являющийся целым типом, определенным во включаемом файле <stddef.h>. Этот оператор позволяет избежать указания машинно-зависимых размеров данных в ваших программах.
Операнд для sizeof может быть одним из следующих:
Имя типа. Чтобы использовать sizeof с именем типа, имя должно быть заключено в скобки.
Выражение. При использовании с выражением sizeof может указываться с круглыми скобками или без них. Выражение не оценивается.
Когда оператор sizeof применяется к объекту типа char , он возвращает 1. Когда оператор sizeof применяется к массиву, он выдает общее количество байтов в этом массиве, а не размер указателя, представленного идентификатором массива. Чтобы получить размер указателя, представленного идентификатором массива, передайте его в качестве параметра функции, которая использует sizeof.
Например:
#include <iostream>
using namespace std;
size_t getPtrSize( char *ptr )
{
return sizeof( ptr );
}
int main()
{
char szHello[] = "Hello, world!";
cout << "The size of a char is: "
<< sizeof( char )
<< "\nThe length of " << szHello << " is: "
<< sizeof szHello
<< "\nThe size of the pointer is "
<< getPtrSize( szHello ) << endl;
}
/*Пример вывода*/
/*The size of a char is: 1
The length of Hello, world! is: 14
The size of the pointer is 4*/
Когда оператор sizeof применяется к классу , структуре или типу объединения , результатом является число байтов в объекте этого типа плюс любые дополнительные отступы, добавленные для выравнивания членов по границам слова. Результат не обязательно соответствует размеру, вычисленному путем добавления требований к хранению отдельных элементов. Параметр компилятора / Zp и прагма пакета влияют на границы выравнивания для элементов. Оператор sizeof никогда не возвращает 0, даже для пустого класса. Оператор sizeof нельзя использовать со следующими операндами:
Функции. (Однако sizeof может применяться к указателям на функции.)
Битовые поля.
Неопределенные классы.
Тип пустоты .
Динамически распределяемые массивы.
Внешние массивы.
Неполные типы.
Заключенные в скобки имена неполных типов.
Когда оператор sizeof применяется к ссылке, результат такой же, как если бы sizeof был применен к самому объекту.
Если массив без размера является последним элементом структуры, оператор sizeof возвращает размер структуры без массива.
Оператор sizeof часто используется для вычисления количества элементов в массиве с использованием выражения в форме:
sizeof array / sizeof array[0]
#include cstddef
int ia[] = { 0, 1, 2 };
// sizeof возвращает размер всего массива
size_t array_size = sizeof ia;
// sizeof возвращает размер типа int
size_t element_size = array_size / sizeof( int );
Применение sizeof к массиву дает количество байтов, занимаемых массивом, а не количество его элементов и не размер в байтах каждого из них. Так, например, в системах, где int хранится в 4 байтах, значением array_size будет 12. Применение sizeof к указателю дает размер самого указателя, а не объекта, на который он указывает:
int *pi = new int[ 3 ];
size_t pointer_size = sizeof ( pi );
Здесь значением pointer_size будет память под указатель в байтах (4 в 32-битных системах), а не массива ia.
//Вот пример программы, использующей оператор sizeof:
#include <string>
#include <iostream>
#include <cstddef>
int main() {
size_t ia;
ia = sizeof( ia ); // правильно
ia = sizeof ia; // правильно
// ia = sizeof int; // ошибка
ia = sizeof( int ); // правильно
int *pi = new int[ 12 ];
cout "pi: " sizeof( pi )
" *pi: " sizeof( pi )
endl;
// sizeof строки не зависит от
// ее реальной длины
string stl( "foobar" );
string st2( "a mighty oak" );
string *ps = stl;
cout " st1: " sizeof( st1 )
" st2: " sizeof( st2 )
" ps: sizeof( ps )
" *ps: " sizeof( *ps )
endl;
cout "short : " sizeof(short) endl;
cout "shorf" : " sizeof(short*) endl;
cout "short : " sizeof(short) endl;
cout "short[3] : " sizeof(short[3]) endl;
}
/*
Результатом работы программы будет:
pi: 4 *pi: 4
st1: 12 st2: 12 ps: 4 *ps:12
short : 2
short* : 4
short : 2
short[3] : 6
*/
Из данного примера видно, что применение sizeof к указателю позволяет узнать размер памяти, необходимой для хранения адреса. Если же аргументом sizeof является ссылка, мы получим размер связанного с ней объекта.
Гарантируется, что в любой реализации С++ размер типа char равен 1
// char_size == 1
size_t char_size = sizeof( char );
Значение оператора sizeof вычисляется во время компиляции и считается константой. Оно может быть использовано везде, где требуется константное значение, в том числе в качестве размера встроенного массива. Например:
// правильно: константное выражение
int array[ sizeof( some_type_T )];