Новый стандарт C++: C++09, Что нас ожидает...

Новый стандарт C++: C++09, Что нас ожидает...
К октябрю 2007 года комитет запланировал публикацию законченного черновика стандарта C++09(который будет доступен публике для рассмотрения и критики).
В октябре 2008 комитет внесёт окончательные коррективы в стандарт и, наконец, на 2009 год запланированна публикация нового стандарта «ISO/IEC 14883(2009): Programming Language C++».

Маленький обзорчик ожидаемых вкусностей, которые готовит нам новый стандарт.

Итак, в кратце, крупные нововведения следующие:

* rvalue references
* template aliases
* variadic templates
* concepts
* unicode characters/strings
* initializer lists
Rvalue References
Появились т.н. ссылки на rvalue. Сначала поясню зачем их вообще изобрели. Исходных проблемы было две: forwarding problem и move semantics.

Forwarding problem
Эта проблема заключается в том, что текущий стандарт, для заданного выражения E(a1,a2,...,aN), которое зависит от параметров a1,a2,...,aN, не позволяет написать такую ф-цию(или функтор), которая будет эквивалентна этому выражению.

Проблема актуальна для разного рода шаблонных обёрток, фабрик, обобщённых функторов и т.п.

За идеал перенаправляющей ф-ции(perfect fowarding function) f(a1,a2,...,aN), которая вызывает g(a1,a2,...,aN) взяли следующие критерии:

* Для всех наборов a1,a2,...,aN, для которых запись g(a1,a2,...,aN) корректна(well-formed), запись f(a1,a2,...,aN) должна быть так же корректна.
* Для всех наборов a1,a2,...,aN, для которых запись g(a1,a2,...,aN) некорректна(ill-formed), запись f(a1,a2,...,aN) должна быть так же некорректна.
* Количество работы, которую придётся проделать для реализации такой идеально-перенаправляющей ф-ции f должно не более чем линейно зависеть от N.

Вот простейший пример:
template
void f(T1 &a1, T2 &a2, T3 &a3)
{
g(a1, a2, a3);
}
Всё бы хорошо, но нельзя сделать вызов f(1, 2, 3).

template
void f(const T1 &a1, const T2 &a2, const T3 &a3)
{
g(a1, a2, a3);
}
Можно сделать вызов f(1, 2, 3), но, если g хотя бы для одного из параметров берёт неконстантную ссылку, то — облом.

template<class /> void f(A1 & a1)
{
g(a1);
}

template<class /> void f(A1 const & a1)
{
g(a1);
}
Для перегруженного варианта всё отлично, кроме 3-го пункта, а именно, при росте числа параметров N, кол-во ф-ций, которые придётся написать, равное 2N, будет расти совсем нелинейно.

Короче говоря, текущий стандарт решить эту проблему не позволяет.

Move semantics
С++ — язык, построенный на семантике копирования(copy semantics). Что такое семантика перемещения(move semantics)? Хороший пример — std::auto_ptr. Его конструктор копирования берёт неконстантную ссылку и перемещает хранимую в исходном объекте сущность в новый объект(тем самым избегая глубокого копирования). Но, несмотря на то, что конструктор копирования auto_ptr берёт неконстантную ссылку, его суть не в том, чтобы изменить объект, а в том, чтобы переместить к себе его содержимое. Так же, семантика перемещения не помешала бы строкам. Вообразим, что строки у нас без подсчёта ссылок. Теперь вообразим, сколько ресурсов будет затрачено на вычисление такого выражения:
string s = string(«123»)+«234»+«567»+«678»+«789»;

будет создано как минимум 5 временных объектов и потом ещё произойдёт глубокое копирование результирующей строки в s(если нету подсчёта ссылок).
А теперь, вообразим, как было бы прекрасно, если бы конструктор копирования умел бы отличать какой объект ему подсунули — временный или нет. Действительно, о временных объектах можно не волноваться и с чистой совестью «забирать» у них выделеный ими буфер, без необходимости глубокого копирования.
К слову, эту проблему можно решить текущими возможностями языка, но очень уж некрасиво…

Что же нам предлагает новый стандарт?
А предлагает он следующее: ввести новый тип ссылок — rvalue reference.
Синтаксис:
T t; // lvalue
T &rt = t; // lvalue reference
T &rrt = t; // rvalue reference

// правила сворачивания ссылок
T cv1 & cv2 & T cv12 &
T cv1 & cv2 && T cv12 &
T cv1 && cv2 & T cv12 &
T cv1 && cv2 && T cv12 &&

Любая именованная rvalue-ссылка трактуется как lvalue.
Любая неименованная rvalue-ссылка трактуется как rvalue.
Т.к. теперь появилась возможность различать тип выражения(lvalue или rvalue), появилась и возможность кастовать lvalue к rvalue: static_cast<T />(lval) будет трактоваться как rvalue.
Возвращаемое значение из ф-ции интерпретируется как rvalue т. е.
return val; return static_cast(val);

Т.о. можно избежать глубокого копирования и ограничиться только лишь перемещением из возвращающей ф-ции в вызвавшую(при наличии соответствующего конструктора).

Forwarding problem решается теперь следующим образом:
void g(long & a1)
{
++a1;
}

template<class /> void f(A1 && a1)
{
g(static_cast<A1 />(a1));
}

int i = 5;
g(i); //fails — int & to long & — запрещённый каст ещё в C++03
f(i); //fails
// A1 выводится(deduced) как int &
// A1 && int & && int &
// a1 — lvalue-reference of int
// static_cast<int />(a1) — lvalue-reference of int
// f(i) не компилируется по тем же причинам, что и не компилируется g(i)

g(1L); // fails — rvalue of long to long & — запрещённый каст ещё в C++03
f(1L); // fails
// A1 выводится как long
// a1 — lvalue of long(named rvalue-reference lvalue)
// static_cast<long />(a1) — rvalue of long(lvalue to rvalue cast)
// f(1L) не компилируется т.к. rvalue to non-const lvalue-reference — запрещённый каст ещё в C++03

long L;
g(L); // ok
f(L); // ok
// A1 выводится как long &
// A1 && long & && long &
// a1 — lvalue-reference of long
// static_cast<long />(a1) — lvalue-reference of long
// f(L) компилируется(как и должна)

Move semantics обеспечивается следующим образом:
class string
{
public:
string(const string &); // copy constructor
string(string &&); // move constructor
string &operator +=(string &); // copy semantics operator +=
string &&operator +=(string &&); // move semantics opertor +=
};

string &&operator +(string &&s1, string &&s2)
{
return s1 += s2;
// т.к. s1 — временный объект, мы не создаём новую строку, мы модифицируем существующую
}

В случаях, когда необходимо вызвать конструктор перемещения для объекта, который не является rvalue, можно сделать каст, запросив необходимое поведение следующим образом:
string s1(«abc»);
string s2 = s1; // construct s2 as s1 copy
string s3 = static_cast<string />(s1); // move from s1 to s2

Лично я эту фичу считаю очень полезной. Особенно, учитывая появившуюся возможность отличать временные объекты от невременных таким образом увеличив производительность в разы, избавившись от лишних операций копирования.

Template aliases

Думаю все оценят эту фичу.
Проблем, побудивших ввести алиасы две.
Первая заключается в том, что очень часто появляется нужда в «шаблонном typedef'е». Wrokaround'ом этой проблемы как правило является следующая конструкция:
template
struct MyVector
{
typedef std::vector type;
};

MyVector::type vec; // не очень красивая запись

Вторая же проблема выражается в том, что при использовании вышеобозначенного workaround'а перестаёт работать вывод шаблонных параметров.
template
void f(std::vector &)
{ }

template
void f2(typename MyVector::type &)
{ }

std::vector v;
MyVector::type v2;
f(v); // ok
f2(v2); // ill-formed

Алиасы позволяют решить обе проблемы. Алиасы представляют из себя объявления. Они не определяют новых типов.

template
using MyVector = std::vector;

using MyFloat = float;

void f1(float) { } // ok
void f1(MyFloat) { } // ill-formed — redefinition

Шаблонные алиасы нельзя специализировать, но, можно специализировать тип синонимом которого является алиас.

Variadic templates

Это нововведение избавляет программиста, реализующего библиотеку списков типов или библиотеку, подобную boost::bind от реализации всех возможных вариаций типа
template
unspecified bind(...);

template
unspecified bind(...);

template
unspecified bind(...);

//…

template
unspecified bind(...);

И позволяет сделать шаблон, принимающий переменное количество шаблонных параметров:
template // здесь троеточие — это синтаксический элемент
R f(Args… args)
{
return g(args...); // вызываем g, передавая ей все аргументы.
}

Как к типам(Args), так и к экземплярам этих типов(args) можно применять разные операторы.
template
R fwd_by_pointer(Args &… args) // R fwd_by_pointer(Arg1 & arg1, Arg2 & arg2, ..., ArgN & argN)
{
return g(&args...); // return g(&arg1, &arg2, ..., &argN);
}

Количество типов в наборе можно узнать с помощью нового оператора sizeof...:
template
struct S
{
enum { result = sizeof...(Types) };
};

Языковых средств для вытягивания типов из набора(Args) нету, но, это не очень сложно делается руками(и уже сделано в стандартной библиотеке — std::tuple и иже с ним). Языковых средств для вытягивания значения из набора(args) вроде как нету, но, опять же, руками это делается несложно — std::tuple тому пример.
В документах встречалось упоминание, что значение можно вытянуть как из массива(args[3], к примеру), но в грамматике я такого упоминания не нашел.

Concepts

Ну это вообще просто сказка :)
Пару слов про сами концепции. Любой, кто использовал обобщённые алгоритмы/структуры данных сталкивался с разного рода требованиями к обобщаемому типу. Наиболее распространенные: DefaultConstructible, CopyConstructible, LessThanComparable. Также, концепциями являются InputIterator, OutputIterator, ForwardIterator, etc. Короче говоря, это требования к обобщаемому типу, невыполнение которых может привести к ошибке инстанцирования шаблона. На данный момент такие требования повсеместно встречаются в документации(IS, boost docs, etc). Теперь эти требования можно будет выражать в коде.

Какие проблемы решат концепции?
Ну, во-первых, это, конечно то, что теперь, тип будет сначала проверятся на соответствие концепции и только после удачного завершения этой проверки, произойдёт попытка инстанцирования шаблона. Т.о. если тип не LessThanComparable, то при попытке использовать его в контейнере map(к примеру) не придётся втыкать на километры выданных компилятором ошибок. Ошибка будет выглядеть примерно так: «тип T не является LessThanComparable», что, замечу, большой плюс. Все, кто использовал boost::bind/lambda::bind оценят :)

Во-вторых, для компилируемого на данный момент клиентского кода, увеличится устойчивость к будущим изменениям в коде библиотеки(гарантии на завтрашний день) — если требование раньше было всего лишь словами и только в следующей версии библиотеки эти слова воплотили в жизнь, то без концепций, некоторый клиентский код может перестать работать, чего не скажешь о коде защищенном концепциями — даже если шаблон мог бы быть инстанцирован, но тип не прошёл проверок на соответствие концепциям, то будет выдана ошибка.

В-третьих, писать обобщённый код станет проще. С концепциями можно делать что только душе угодно. К примеру, если тип vector не соответствует концепции Stack(у него нету ф-ций push/pop), но, принципиально его можно использовать как тип соответствующий этой концепции(можно использовать ф-ции push_back/pop_back), то, без потери для общности, можно написать что-то вроде адаптера(concept_map), который будет приспосабливать данный тип к заданной концепции. Концепциями можно защитить не весь класс, а только некоторые его методы. Также, можно разработать несколько версий алгоритма эффективных для той или иной концепции и перегрузить его так, что будет выбран наиболее подходящий алгоритм.

Синтаксис концепций интуитивно понятен и поясню я только некоторые моменты.
// вот так определяются концепции
auto concept LessThanComparable
{
bool operator<(T, T);
};

template // вот так предъявляются требования к типу T
const T& min(const T& x, const T& y)
{
return x < y? x: y;
}

template
where LessThanComparable // или можно предъявить требования так
const T& min(const T& x, const T& y)
{
return x < y? x: y;
}

// пример более объёмной концепции
auto concept Regular
{
T::T(); // default constructor
T::T(const T&); // copy constructor
T::~T(); // destructor
T& operator=(T&, const T&); // copy assignment
bool operator==(T, T); // equality comparison
bool operator!=(T, T); // inequality comparison
void swap(T&, T&); // swap
};

// ещё пример
auto concept Convertible />
{
operator U(T);
};

template
where Convertible // концепции можно использовать для задания некоторых взаимоотношений между несколькими типами
U convert(const T& t)
{
return t;
}

// итератор
auto concept InputIterator
{
typename value_type; // ассоциированные типы
typename reference;
typename pointer;
typename difference_type;
where Regular<Iter />; // вложенные требования
where Convertible;
reference operator*(Iter); // dereference
Iter& operator++(Iter&); // pre-increment
Iter operator++(Iter&, int); // post-increment
//…
};

template />
where Regular
Iter find(Iter first, Iter last, const Iter::value_type& value)
{
while (first != last && *first != value)
++first;
return first;
}

auto concept BinaryFunction/>
{
typename result_type;
result_type operator()(F&, T1, T2);
};

auto concept BinaryPredicate/>
: BinaryFunction // пример «наследования» концепций
{
where Convertible;
};

// уточнение для char * у которого нету ассоциированных с ним типов
// аналог traits, только намного более мощный(см. далее)
concept_map InputIterator
{
typedef char value_type;
typedef char& reference;
typedef char* pointer;
typedef std:: ptrdiff_t difference_type;
};

concept Stack/>
{
typename value_type;
void push(X&, value type);
void pop(X&);
value type top(const X&);
bool empty(const X&);
};

// пример адаптации вектора к концепции Stack
template/>
concept_map Stack< std::vector<T /> >
{
typedef T value_type;
void push(std:: vector<T />& v, T x) { v. push_back(x); }
void pop(std:: vector<T />& v) { v. pop_back(); }
T top(const std:: vector<T />& v) { return v.back(); }
bool empty(const std::vector<T />& v) { return v.empty(); }
};

// концепция, которой удовлетворяет вектор(и не только)
concept BackInsertionSequence/>
{
typename value_type = X::value type;
void X::push_back(value type);
void X::pop_back();
value_type& X::back();
const value_type& X::back() const;
bool X::empty() const;
};

// пример, как можно адаптировать любой тип, удовлетворяющий концепции C1, к концепции C2.
// другими словами, как адаптировать одну концепцию к другой
template/>
concept_map Stack<X />
{
typedef X::value_type value_type;
void push(X& x, value_type value ) { x. push_back(value); }
void pop(X& x) { x. pop_back(); }
T top(const X& x) { return x.back(); }
bool empty(const X& x) { return x.empty(); }
};

// пример перегрузки на основе концепций — будет выбрана самая «специфичная» форма
//т.е. для BidirectionalIterator будет выбран второй вариант, несмотря на то, что удовлетворяет и первый(InputIterator)
template/>
void advance(Iter& x, Iter::difference type n)
{
while (n > 0) { ++x; --n; }
}
template/>
void advance(Iter& x, Iter::difference type n)
{
if (n > 0) while (n > 0) { ++x; --n; }
else while (n < 0) { --x; ++n; }
}
template/>
void advance(Iter& x, Iter::difference type n)
{
x += n;
}

// пример разных реализаций контейнера для разных хранимых типов данных
template/>
class dictionary
{
// slow, linked-list implementation
};
template/>
where !Hashable<T />
class dictionary<T />
{
// balanced binary tree implementation
};
template/>
class dictionary<T />
{
// hash table implementation
};

// пример, как можно обложить ограничениями не весь класс, а только некоторые ф-ции(причём разными ограничениями)
template/>
struct pair
{
where DefaultConstructible<T /> && DefaultConstructible<U />
pair(): first(), second() { }

where CopyConstructible<T /> && CopyConstructible<U />
pair(const T& t, const U& u): first(t), second(u) { }

where Destructible<T /> && Destructible<U />
~pair() { }

where Assignable<T /> && Assignable<U />
pair& operator=(const pair& other)
{
first = other.first;
second = other.second;
}

T first;
U second;
};

// ещё пример, как помимо CopyConstructible, может понадобится DefaultConstructible
// но вектор может ф-ционировать и без второго требования потому его(требование) относят только к отдельной ф-ции.
template/>
class vector
{
public:
// обратите внимание, как одна ф-ция разделилась на две, дабы добавить контейнеру общности :)

// vector(size t n, const T& value = T());
vector(size t n, const T& value);

where DefaultConstructible<T /> vector(size t n);
};

Ключевое слово where в последней версии вроде как решили заменить на слово requires.

Unicode characters/strings
Ну, собственно, ничего интересного, кроме самого факта: теперь в С++ оффициальная поддержка UTF-16(u"...") и UTF-32(U"..."). Ну а факт, я считаю, немаловажный и вполне достойный соответствующего внимания со стороны публики :)
Появились новые типы char16_t и char32_t.
Также, отдельно рассматривается добавление UTF-8(E"...").

Initializer lists

X t1 = v; // «copy initialization» possibly copy construction
X t2(v); // direct initialization
X t3 = { v }; // initialize using initializer list <<<=================
X t4 = X(v); // make an X from v and copy it to t4

Достаточно обширное нововведение. Пока всех подробностей не выяснил, но, в двух словах постараюсь рассказать.
В языках типа C# практикуется такое:
f(new char[] {'1', 'a', '-'});

В С++09 предполагается нечто подобное(только без new :)).
Теперь можно будет написать
std::vector v = { 1, 2, 3, 4, 5 };

Как написать класс, чтобы его можно было вот так инициализировать?
#include // этот хэдер предоставляет класс std::initializer_list

namespace std
{
template/> class initializer_list
{
// representation implementation defined
// (probably two pointers or a pointer and a size)
// implementation defined constructor

public:
// default copy construction and copy assignment
// no default constructor
// default trivial destructor

constexpr int size() const; // number of elements
const T* begin() const; // first element
const T* end() const; // one-past-the-last element
};
}

class A
{
public:
A(std::initializer_list a) { /*… */ }
//…
};

class B
{
public:
B(std::initializer_list a) { /*… */ }
//…
};

void f(const A &a); // #1
void f(const B &b); // #2

int main
{

A a1 = {1, 2, 3};
A a2{2, 3, 4};
A a3;
a3 = A{3, 4, 5};

f({1, 2., 3}); // ambiguity
f(A{1, 2., 3}); // #1
f(B{1, 2., 3}); // #2
f({1., 2., 3.}); // #2
f{'a', 'b', 'c'}; // #1

return 0;
}

Синтаксические мелочи

static_assert
Новое ключевое слово, позволяет во время компиляции сделать проверку и, в случае чего, сгенерить ошибку компиляции(текст ошибки можно указывать).
Наибольшее применение, имхо, будет иметь в шаблонах, хотя, с появлением концепций — сомнительно :).
Так же, возможно использование как замена старой доброй директивы #error.
template />
struct Check
{
static_assert(sizeof(int) second.begin(), e2 = i1->second.end(); i2 != e2; ++i2)
for (auto i3 = i2->second.begin(), e3 = i2->second.end(); i3 != e3; ++i3)
for(auto i4 = i3->begin(), e4 = i3->end(); i4 != e4; ++i4)
{
/*… */
}

// ещё, появилась штука, ожидаемая под названием typeof.
// в C++09 её назвали decltype
decltype(container.begin()) i = container.begin();

Extended friend Declarations
class C;
typedef C Ct;

class X1
{
friend C; // OK: class C is a friend
};
class X2
{
friend Ct; // OK: class C is a friend
};
class X3
{
friend class Ct; // C++09 — ok, C++03 — ill-formed
};

Extern templates
template
class MyVector { /*… */ };

template class MyVector; // explicit instantination

extern tempalte class MyVector; // extern explicit instantination

сделано для того, чтобы диначическая библиотека могла сделать у себя explicit instantination, а клиент у себя extern explicit instantintaion

Right Angle Brackets
std::vector<std::set<int>> v; // C++03 — ill-formed, C++09 — well-formed

Range-based for-loop
int array[5] = { 1,2,3,4,5 };
std::vector vec = { 1, 2, 3, 4, 5 }; // так инициализировать нельзя, но мы это опустим :)
for ( auto& x: array )
x *= 2;

for ( float x: vec )
std::cout << x << std::endl;

C99 Compatibility: __func__
namespace N { void f(); }
void N::f() { } // __func__ is «f»

struct S
{
S(): s(__func__) { } // ok, s points to «S»
~S() { } // __func__ is "~S"
operator int() { } // __func__ is «conversion operator»
template/> int g();
const char *s;
};
S operator +(S,S) { } // __func__ is «operator+»
template<> int S::g<int />() { } // __func__ is «g»

struct S
{
S(): s(__func__) { } // ok
const char *s;
};
void f(const char * s = __func__); // error: __func__ is undeclared

Generalized Constant Expressions
constexpr — новое ключевое слово.
Суть нововведения в том, что теперь, например, можно как размерность массива использовать результат, возвращенный ф-цией.
struct A
{
constexpr A(int i): val(i) { }
constexpr operator int() { return val; }
constexpr operator long() { return 43; }
private:
int val;
};

template<int /> struct X { };
constexpr A a = 42;
X<a /> x; // OK: unique conversion to int
int ary[a]; // error: ambiguous conversion

Explicit Conversion Operators
class T { };
class X
{
public:
explicit operator T() const;
};

int main()
{
X x;
// Direct initialization:
T t4( x );
// Copy initialization:
T t8 = x; // error

// Cast notation:
T t12 = (T) x;

// Static_cast:
T t16 = static_cast<T />( x );

// Function-style cast:
T t20 = T( x );
return 0;
}

Raw String Literals
char *s1 = "('(?:[^\\\\']|\\\\.)*'|\"(?:[^\\\\\"]|\\\\.)*\")|";
char *s2 = R"[('(?:[^\\']|\\.)*'|"(?:[^\\"]|\\.)*")|]" // кто работал с regex на с++ — оценят :)
// post: strcmp(s1, s2) == 0

char *s3 =
"
"
"
"
«Auto-generated html formated source
»
"
"
"
"
"
"
"
"
"<PRE />
";

char *s4 =
R"[\

Auto-generated html formated source


<PRE />
]"

// post: strcmp(s3, s4) == 0

A name for the null pointer: nullptr
char* ch = nullptr; // ch has the null pointer value
char* ch2 = 0; // ch2 has the null pointer value
int n = nullptr; // error
int n2 = 0; // n2 is zero
if( ch == 0 ); // evaluates to true
if( ch == nullptr ); // evaluates to true
if( ch ); // evaluates to false
if( n2 == 0 ); // evaluates to true
if( n2 == nullptr ); // error
if( nullptr ); // error, no conversion to bool
if( nullptr == 0 ); // error

// arithmetic
nullptr = 0; // error, nullptr is not an lvalue
nullptr + 2; // error

Alignment Support
// новые ключевые слова: alignas, alignof
const std::size_t align_of_int = alignof(int);
T alignas(T) alignas(long) t1;
T alignas(T) alignas(align_of_int) t2;

Prohibited access specifier
template
struct owned_ptr
{
public:
explicit owned_ptr( T * p ): pt( p ) {}
~owned_ptr() { delete pt; }

T * operator->() { return pt; }
T const * operator->() const { return pt; }

private:
T * pt;
void foo();

prohibited:
owned_ptr( owned_ptr const & );
owned_ptr & operator=( owned_ptr const & );
};
template
void S::foo()
{
new owned_ptr(*this); // compile-time error(не link-time)
}

Explicit class and default definitions
class A
explicit
{
// no implicitly declared/defined special member functions(default ctor, copy ctor, copy assignment operator, destructor)
};

class B
explicit
{
public:
B() {default} // default ctor definition(compiler generated)
};

class I
explicit
{
public:
virtual ~I() {default}
};

Defaulted and Deleted Functions
struct type
{
type() = default; // trivial
virtual ~type() = default; // non-trivial because virtual
type & operator =( const type & ); // declaration and…
};
inline // the inline definition keeps it trivial
type & type::operator =( const type & ) = default;

// — struct type
{
type( const type & ); // declaration and…
};
type::type() = default; // the non-inline makes it non-trivial

// — struct type
{
type & operator =( const type & ) = delete;
type( const type & ) = delete;
type() = default;
};
// — struct type
{
void * operator new( std::size_t ) = delete;
};
// — struct type
{
~type() = delete; // disable destructor
};
// — struct type
{
type( long long ); // can initialize with an long long
type( long ) = delete; // but not anything less
};
extern void bar( type, long long ); // and the same for bad overloads
void bar( type, long ) = delete; // of free functions
// — struct type
{
type( long long );
explicit type( long ) = delete;
};
extern void function( type );
function( type( 42 ) ); // error 42 promotes to long
function( 42 ); // okay type(long long); type(long) not considered

Pure implementation method declaration
struct Base
{
virtual void f1() = 0;
virtual void f2() = 0;
};

struct S
: public Base
{
virtual void f1() > 0; // должно быть определение S::f1, иначе compile-time error
virtual void f2() >= 0; // определение S::f2 может быть, а может и не быть :)
virtual void f3() > 0; // compile-time error — нету объявления Base::f3.
virtual void f4() >= 0; // compile-time error — нету объявления Base::f3.
};

Strongly Typed Enums
enum class E { E1, E2, E3 = 100, E4 /* = 101 */ };
void f( E e )
{
if( e >= 100 ); // error: no E to int conversion
}
int i = E::E2; // error: no E to int conversion
// — enum class E { E1, E2, E3 = 100, E4 /* = 101 */ };
E e1 = E1; // error
E e2 = E::E2; // ok
// — enum class E: unsigned long { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U };
unsigned long ul = E::Ebig;

Формальные мелочи

Conditionally-Supported Behavior
Добавлен новый вид определяемого стандартом поведения.
Теперь, конструкции для которых поведение было неопределено(UB), считаются conditionally-supported и могут интерпретировать либо как implementation-defined, либо как ill-formed.

Замена некоторых UB на Diagnosable Errors
К примеру, теперь передача non-POD в элипсис приведёт к ошибке компиляции, а не к UB как в C++03.

Новая модель выполнения программы
В связи с добавлением оффициальной поддержки multithreading.
Убрали понятие sequence point.
Добавили понятие evaluation — набор выборок(чтение значения переменной) и side effects, которые происходят в ходе вычисления выражения.
Понятие sequence point заменили аж тремя понятиями sequencing constraints: sequenced before, unsequenced, indeterminately sequenced. Эти понятия — отношения между двумя evaluations A и B(A sequenced before B, A and B unsequenced, etc).
Теперь порядок вычисления операндов не unspecified. Теперь evaluations of operands unsequenced :)
В связи с отсутствием понятия sequence point вычисление операндов операторов «a && b», «a || b», «a? b: c» и «a, b» примерно следующее: evaluation of a is sequenced before evaluation of b.

Облегчение ограничений на POD'ы
Ввели два новых понятия: trivial-class и standard-layout-class. POD — это класс, который является одновременно и trivial и standard-layout.
Теперь все гарантии, которые давал POD можно разделить на 2 части: первые даются для trivial типов, вторые для standard-layout.
В общем теперь большее кол-во типов будет поддаваться копированию посредством memcpy и т.п.

Перегрузка операторов
Рассматривается возможность перегрузки операторов
.
.*
static_cast<>
const_cast<>
dynamic_cast<>

Стандартная библиотека

Дополнение к этому пункту и/или более подробные описания фич можно увидеть здесь:
Новый стандарт C++. C++09 (сообщение #1601275)

cstdint из C99
Добавленна опциональная поддержка типов с размером точно соответствующим указанному.
int8_t, int16_t, int32_t, int64_t
uint8_t, uint16_t, uint32_t, uint64_t

Обязательная поддержка для типов с размером не меньшим указанного.
int_least8_t, int_least16_t, etc.
uint_least8_t, etc.

И обязательная поддержка типов с размером точно соответствующим указанному, но, возможно, более быстрых, чем их least-эквиваленты.
int_fast8_t, etc.
uint_fast8_t, etc.

Контейнеры
Sequence container: std::array — см. ниже «Перешло из boost».
Unordered associative containers:
unordered_map, unordered_multimap,
unordered_set, unordered_multiset
Вполне ожидаемые контейнеры работающие по принципу хэширования, ранее известные под названием hash_set/map в «вольных» реализациях STLport, MS VC-8.0.

В связи с введением rvalue-reference и move semantics
Во-первых, повсеместное добавление/переведение вышеобозначенной семантики для повышения производительности(там, где это возможно).
Добавлены ф-ции помошники move и forward, означающие не что иное, как прямое предназначение rvalue-ссылок. Первая вынуждает использовать семантику перемещения даже если операнд — lvalue(-reference). Вторая осуществляет необходимые телодвижения для достижения perfect forwarding :)

Добавлен move_iterator, который работает точно также, как Iter, за исключением того, что его dereferencing оператор принуждает использовать семантику перемещения.

В связи с введением constexpr
Много где встречаются эти константные ф-ции(результат которых можно использовать даже для определения статического массива).
К примеру numeric_limits. Теперь его ф-ции min/max отвечают соответствующим требованиям.

Перешло из boost
std::tuple
Тож самое, что и boost::tuple, за одним отличием — переведён на синтаксис variadic templates.

std::bind
Тож самое, что и boost::bind, за одним отличием — переведён на синтаксис variadic templates.

std::array(sequence container)
Тож самое, что и boost::array. Вроде где-то упоминалось, что собираются сделать его N-мерным(в отличие от 1-мерного boost::array).

std::regex
См. boost::regex

Многопоточность
Ничего не могу сказать более определённого, чем то, что в новом С++ будет поддержка многопоточности и будет предоставленно API, совместимое с posix pthreads. Также, возможность выполнения атомарных операций(необходимо для синхронизации — реализации спин-локов)
  • +8
  • 15 декабря 2008, 17:21
  • azazello

Комментарии (11)

RSSсвернуть /развернуть
+
+1
  че за хрень
avatar

SYLOR

  • 15 декабря 2008, 17:57
+
+4
Аааа мой комп в ауте от этого
avatar

Jedi_Knight

  • 15 декабря 2008, 18:40
+
+2
Мой мосг в ауте, хотя много интересного .
Они про Си забыли? C99 онли под линух, под виндас только через эмули =(
avatar

Psihx

  • 15 декабря 2008, 19:27
+
+4
респект тем людям кто это смог прочитать…
З.Ы. я не смог)
avatar

LosTic

  • 15 декабря 2008, 20:23
+
+1
ааааааааа, мой моск взорвалсо
avatar

chudnyj-fejs

  • 15 декабря 2008, 20:38
+
+2
мдя… что-то не похоже на информационно-развлекательный портал
avatar

smiq

  • 15 декабря 2008, 22:32
+
+2
agМне камент ыбольше чем новость нравятся )
avatar

sLaWa

  • 15 декабря 2008, 23:07
+
0
LosTic,
ag
avatar

M4

  • 16 декабря 2008, 00:05
+
0
эээ… хм… мне вообще жестко понравилось!!! Давай побольше таких!!! Еще есть что нибудь вот про
}
template
void advance(Iter& x, Iter::difference type n)
{
if (n > 0) while (n > 0) { ++x; --n; }
else while (n < 0) { --x; ++n; }
}
template
void advance(Iter& x, Iter::difference type n)
{
x += n;

?????????????
avatar

chet

  • 16 декабря 2008, 01:23
+
0
афтор, слышишь?, никогда,  слышишь?!  не пости эту хрень тут!!!
avatar

-RoveR-

  • 16 декабря 2008, 02:27
+
0
аффтар зачет, самое то, что все ждали на развлекательном портале
avatar

VovanS

  • 16 декабря 2008, 17:41

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.
Валидный HTMLВалидный CSSRambler's Top100