template
unsigned count_args(Args ... args) {
return sizeof... (Args);
}
Как и для обычного оператора sizeof
, результатом sizeof...
является константное выражение, которое, следовательно, можно использовать для задания границ массива и т.п.
А.7. Автоматическое выведение типа переменной
С++ — статически типизированный язык: тип любой переменной известен на этапе компиляции. Более того, программист обязан указать тип каждой переменной. В некоторых случаях имена оказываются очень громоздкими, например:
std::map> m;
std::map>::iterator
iter = m.find("my key");
Традиционно для решения этой проблемы использовались псевдонимы типов ( typedef
), позволяющие сократить длину идентификатора типа и избавиться от потенциальных проблем несовместимости типов. Этот способ работает и в C++11, но появился и новый: если переменная инициализируется в объявлении, то в качестве ее типа можно указать auto
. Тогда компилятор автоматически выведет тип переменной из типа инициализатора. Следовательно, приведенный выше пример итератора можно записать и так:
auto iter = m.find("my key");
Спецификатор auto
необязательно употреблять изолированно; его можно использовать в сочетании с другими спецификаторами для объявления const
-переменных, а также указателей и ссылок. Вот несколько примеров объявления переменных с помощью auto
и дополнительных конструкций:
auto i = 42; // int
auto& j = i; // int&
auto const k = i; // int const
auto* const p = &i; // int * const
Правила выведения типа переменной основаны на правилах, применяемых в другом месте языка, где выводятся типы: параметры шаблонов функций. В объявлении вида
Какое-то-типовое-выражение-включающее-auto
var = some-expression;
переменная var
имеет тот же тип, который был бы выведен, если бы она встречалась в качестве параметра шаблона функции, объявленного с таким же типовым выражением, только auto
заменяется именем типового параметра шаблона:
template
void f(type-expression var);
f(some-expression);
Это означает, что тип массива сводится к указателю, а ссылки опускаются, если только в типовом выражении переменная явно не объявлена как ссылка. Например:
int some_array[45];
auto p = some_array; // int*
int& r = *p;
auto x = r; // int
auto& y = r; // int&
Это позволяет существенно упростить объявление переменных, особенно в случаях, когда полный идентификатор типа очень длинный или даже неизвестен (например, тип результата вызова функции в шаблоне).
А.8. Поточно-локальные переменные
У поточно-локальной переменной имеется отдельный экземпляр в каждом потоке программы. Для объявления поточно-локальной переменной служит ключевое слово thread_local
. Поточно-локальными могут быть переменные с областью видимости пространства имен, статические члены классов и локальные переменные. Говорят, что они имеют потоковое время жизни (thread storage duration):
thread_local int x;←┐
Поточно-локальная переменная в
│
области видимости пространства
│
имен
class X │
Поточно-локальная
{ │
статическая пере-
static thread_local std::string s;←┘
менная-член класса
};
│
Необходимо
static thread_local std::string X::s; ←┘
определение X::s
void foo() {
│
Поточно-локальная
thread_local std::vector v;←┘
локальная переменная
}
Поточно-локальные переменные в области видимости пространства имен и поточно-локальные статические члены класса конструируются раньше первого использования переменной в той же единице трансляции, но насколько раньше не оговаривается. В одних реализациях поточно-локальные переменные могут конструироваться при запуске потока, в других — непосредственно перед первым использованием в каждом потоке, в третьих — еще в какой-то момент. Возможен и смешанный подход в зависимости от контекста. На самом деле, если ни одна из поточно-локальных переменных в данной единице трансляции не используется, то не гарантируется, что они вообще будут сконструированы. Это позволяет динамически загружать модули, содержащие поточно-локальные переменные — они будут сконструированы в данном потоке при первом обращении потока к переменной из динамически загруженного модуля.
Поточно-локальные переменные, объявленные внутри функции, инициализируются, когда поток управления впервые проходит через объявление переменной в данном потоке. Если функция в данном потоке не вызывалась, то объявленные в ней поточно-локальные переменные не будут сконструированы. Точно такое же поведение характерно для локальных статических переменных, только в этом случае оно применяется в каждом потоке по отдельности.
Читать дальше