search

Условный тернарный оператор

Тернарный оператор ?: позволяет сократить определение простейших условных конструкций 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 )];