На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
Модераторы: JoeUser, Qraizer, Hsilgos
Страницы: (74) [1] 2 3 ...  73 74  ( Перейти к последнему сообщению )  
> Текущий Стандарт С++ и перспективы его развития
    К октябрю 2007 года комитет запланировал публикацию законченного черновика стандарта C++09(который будет доступен публике для рассмотрения и критики).
    В октябре 2008 комитет внесёт окончательные коррективы в стандарт и, наконец, на 2009 год запланированна публикация нового стандарта "ISO/IEC 14883(2009): Programming Language C++".

    Надеюсь, не мне одному интересно, что же ожидает нас в новом С++. Потому, проштудировав документы, доступные обычным смертным на сайте open-std.org, я сделал маленький обзорчик ожидаемых вкусностей, которые готовит нам новый стандарт.

    Итак, в кратце, крупные нововведения следующие:
    • rvalue references
    • template aliases
    • variadic templates
    • concepts
    • unicode characters/strings
    • initializer lists

    Примечание: имеется так же обзор того, чего НЕ будет в С++09. Новый стандарт C++: C++09 (сообщение #1602819)



    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.

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

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

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


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


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

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

    Что же нам предлагает новый стандарт?
    А предлагает он следующее: ввести новый тип ссылок - rvalue reference.
    Синтаксис:
    ExpandedWrap disabled
      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 т. е.
    ExpandedWrap disabled
      return val; <=> return static_cast<ret_T &&>(val);

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

    Forwarding problem решается теперь следующим образом:
    ExpandedWrap disabled
      void g(long & a1)
      {
          ++a1;
      }
       
      template<class A1> 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 обеспечивается следующим образом:
    ExpandedWrap disabled
      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, можно сделать каст, запросив необходимое поведение следующим образом:
    ExpandedWrap disabled
      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'ом этой проблемы как правило является следующая конструкция:
    ExpandedWrap disabled
      template < class T >
      struct MyVector
      {
          typedef std::vector< T, MyAllocator< T > > type;
      };
       
      MyVector< int >::type vec; // не очень красивая запись

    Вторая же проблема выражается в том, что при использовании вышеобозначенного workaround'а перестаёт работать вывод шаблонных параметров.
    ExpandedWrap disabled
      template < class T >
      void f(std::vector< T > &)
      { }
       
      template < class T >
      void f2(typename MyVector< T >::type &)
      { }
       
      std::vector< int > v;
      MyVector< int >::type v2;
      f(v); // ok
      f2(v2); // ill-formed

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

    ExpandedWrap disabled
      template < class T >
      using MyVector = std::vector< T, MyAllocator< T > >;
       
      using MyFloat = float;
       
      void f1(float) { }   // ok
      void f1(MyFloat) { } // ill-formed - redefinition

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






    Variadic templates


    Это нововведение избавляет программиста, реализующего библиотеку списков типов или библиотеку, подобную boost::bind от реализации всех возможных вариаций типа
    ExpandedWrap disabled
      template < class R >
      unspecified bind(...);
       
      template < class R, class A1 >
      unspecified bind(...);
       
      template < class R, class A1, class A2 >
      unspecified bind(...);
       
      // ...
       
      template < class R, class A1, class A2, ..., class AN >
      unspecified bind(...);

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

    Как к типам(Args), так и к экземплярам этих типов(args) можно применять разные операторы.
    ExpandedWrap disabled
      template < class R, class... Args >
      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...:
    ExpandedWrap disabled
      template < class... Types >
      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), который будет приспосабливать данный тип к заданной концепции. Концепциями можно защитить не весь класс, а только некоторые его методы. Также, можно разработать несколько версий алгоритма эффективных для той или иной концепции и перегрузить его так, что будет выбран наиболее подходящий алгоритм.

    Синтаксис концепций интуитивно понятен и поясню я только некоторые моменты.
    ExpandedWrap disabled
      // вот так определяются концепции
      auto concept LessThanComparable< typename T >
      {
          bool operator<(T, T);
      };
       
      template< LessThanComparable T > // вот так предъявляются требования к типу T
      const T& min(const T& x, const T& y)
      {
          return x < y ? x : y;
      }
       
      template < typename T >
          where LessThanComparable< T > // или можно предъявить требования так
      const T& min(const T& x, const T& y)
      {
          return x < y? x : y;
      }
       
      // пример более объёмной концепции
      auto concept Regular < typename T >
      {
          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 <typename T, typename U>
      {
          operator U(T);
      };
       
       
      template < typename U, typename T >
          where Convertible< T, U > // концепции можно использовать для задания некоторых взаимоотношений между несколькими типами
      U convert(const T& t)
      {
          return t;
      }
       
       
      // итератор
      auto concept InputIterator < typename Iter >
      {
      typename value_type; // ассоциированные типы
      typename reference;
      typename pointer;
      typename difference_type;
      where Regular<Iter>; // вложенные требования
      where Convertible<reference_type, value_type>;
      reference operator*(Iter); // dereference
      Iter& operator++(Iter&); // pre-increment
      Iter operator++(Iter&, int); // post-increment
      // ...
      };
       
      template <InputIterator Iter>
          where Regular<Iter::value_type>
      Iter find(Iter first, Iter last, const Iter::value_type& value)
      {
          while (first != last && *first != value)
              ++first;
          return first;
      }
       
       
      auto concept BinaryFunction<typename F, typename T1, typename T2>
      {
          typename result_type;
          result_type operator()(F&, T1, T2);
      };
       
      auto concept BinaryPredicate<typename F, typename T1, typename T2>
          : BinaryFunction<F, T1, T2> // пример "наследования" концепций
      {
          where Convertible<result_type, bool>;
      };
       
       
      // уточнение для char * у которого нету ассоциированных с ним типов
      // аналог traits, только намного более мощный(см. далее)
      concept_map InputIterator<char*>
      {
          typedef char value_type ;
          typedef char& reference ;
          typedef char* pointer ;
          typedef std:: ptrdiff_t difference_type ;
      };
       
       
      concept Stack<typename X>
      {
          typename value_type;
          void push(X&, value type);
          void pop(X&);
          value type top(const X&);
          bool empty(const X&);
      };
       
      // пример адаптации вектора к концепции Stack
      template<typename T>
      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 X>
      {
          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<BackInsertionSequence X>
      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<InputIterator Iter>
      void advance(Iter& x, Iter::difference type n)
      {
          while (n > 0) { ++x; --n; }
      }
      template<BidirectionalIterator Iter>
      void advance(Iter& x, Iter::difference type n)
      {
          if (n > 0) while (n > 0) { ++x; --n; }
          else while (n < 0) { --x; ++n; }
      }
      template<RandomAccessIterator Iter>
      void advance(Iter& x, Iter::difference type n)
      {
          x += n;
      }
       
      // пример разных реализаций контейнера для разных хранимых типов данных
      template<EqualityComparable T>
      class dictionary
      {
          // slow, linked-list implementation
      };
      template<LessThanComparable T>
          where !Hashable<T>
      class dictionary<T>
      {
          // balanced binary tree implementation
      };
      template<Hashable T>
      class dictionary<T>
      {
          // hash table implementation
      };
       
       
      // пример, как можно обложить ограничениями не весь класс, а только некоторые ф-ции(причём разными ограничениями)
      template<typename T, typename U>
      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<T, U>& other)
          {
              first = other.first;
              second = other.second;
          }
       
          T first;
          U second;
      };
       
       
      // ещё пример, как помимо CopyConstructible, может понадобится DefaultConstructible
      // но вектор может ф-ционировать и без второго требования потому его(требование) относят только к отдельной ф-ции.
      template<CopyConstructible T>
      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


    ExpandedWrap disabled
      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# практикуется такое:
    ExpandedWrap disabled
      f(new char[] {'1', 'a', '-'});

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

    Как написать класс, чтобы его можно было вот так инициализировать?
    ExpandedWrap disabled
      #include <initializer_list> // этот хэдер предоставляет класс std::initializer_list
       
      namespace std
      {
      template<class E> 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< char > a) { /* ... */ }
          // ...
      };
       
      class B
      {
      public:
          B(std::initializer_list< double > 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.
    ExpandedWrap disabled
      template <typename T>
      struct Check
      {
          static_assert(sizeof(int) <= sizeof(T), "not big enough");
      };




    Расширенная функциональность sizeof
    ExpandedWrap disabled
      struct C
      {
         some_type m;
         // ...
      };
       
      const std::size_t sz = sizeof(C::m); // C++03 - error, C++09 - ok




    Delegating Constructors
    ExpandedWrap disabled
      // C++03 workaround
      class A
      {
          void Init(/* ... */) { /* ... */ }
      public:
          A()
          { Init(); };
          A(/* ... */)
          { Init(); /* ... */ }
      };
       
      // C++09 well-formed code
      class A
      {
      public:
          A()
          { /* initializations */ };
          A(/* ... */)
              : A() // <<==== delegating construction
          { /* other initializations */ }
      };




    Inheriting Constructors
    ExpandedWrap disabled
      struct B1 {
        B1( int, int ) {}
      };
       
      struct B2 {
        B2( double, double ) {}
      };
       
      struct D1 : B1 {
        using B1::B1;  // impliclty declare D1( int a1, int a2 ) : B1(a1, a2) {}
        int x;
      };
       
      struct D2 : B2 {
        using B2::B2; // impliclty declare D2( double a1, double a2 ) : B2(a1, a2) {}
        B1 b;
      };




    Deducing the type of variable from its initializer expression.
    Достаточно интересная штука... настолько же, насколько и опасная, имхо...
    ExpandedWrap disabled
      int foo();
      auto x1 = foo(); // x1 : int
      const auto& x2 = foo(); // x2 : const int&
      auto& x3 = foo(); // x3 : int&: error, cannot bind a reference to a temporary
      float& bar();
      auto y1 = bar(); // y1 : float
      const auto& y2 = bar(); // y2 : const float&
      auto& y3 = bar(); // y3 : float&
      A* fii();
      auto* z1 = fii(); // z1 : A*
      auto z2 = fii(); // z2 : A*
      auto* z3 = bar(); // error, bar does not return a pointer type
       
      // из очень полезных применений вижу следующее
      // особенно полезно при замене контейнера(-ов) на концептуально аналогичные, но по типизации разные
      std::map< std::string, std::map< std::string, std::set< std::vector< bool > > > > container;
      for (auto i1 = container.begin(), e1 = container.end(); i1 != e1; ++i1)
          for (auto i2 = i1->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
    ExpandedWrap disabled
      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
    ExpandedWrap disabled
      template < class T >
      class MyVector { /* ... */ };
       
      template class MyVector< int >; // explicit instantination
       
      extern tempalte class MyVector< int >; // extern explicit instantination

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



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




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




    C99 Compatibility: __func__
    ExpandedWrap disabled
      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<class T> 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 - новое ключевое слово.
    Суть нововведения в том, что теперь, например, можно как размерность массива использовать результат, возвращенный ф-цией.
    ExpandedWrap disabled
      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
    ExpandedWrap disabled
      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
    ExpandedWrap disabled
      char *s1 = "('(?:[^\\\\']|\\\\.)*'|\"(?:[^\\\\\"]|\\\\.)*\")|";
      char *s2 = R"[('(?:[^\\']|\\.)*'|"(?:[^\\"]|\\.)*")|]" // кто работал с regex на с++ - оценят :)
      // post: strcmp(s1, s2) == 0
       
       
      char *s3 =
      "<HTML>\n"
      "<HEAD>\n"
      "<TITLE>Auto-generated html formated source</TITLE>\n"
      "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=windows-1252\">\n"
      "</HEAD>\n"
      "<BODY LINK=\"#0000ff\" VLINK=\"#800080\" BGCOLOR=\"#ffffff\">\n"
      "<P> </P>\n"
      "<PRE>\n";
       
      char *s4 =
      R"[\
      <HTML>
      <HEAD>
      <TITLE>Auto-generated html formated source</TITLE>
      <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
      </HEAD>
      <BODY LINK="#0000ff" VLINK="#800080" BGCOLOR="#ffffff">
      <P> </P>
      <PRE>
      ]"
       
      // post: strcmp(s3, s4) == 0




    A name for the null pointer: nullptr
    ExpandedWrap disabled
      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
    ExpandedWrap disabled
      // новые ключевые слова: 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
    ExpandedWrap disabled
      template< typename T >
      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< typename T >
      void S< T >::foo()
      {
          new owned_ptr(*this); // compile-time error(не link-time)
      }




    Explicit class and default definitions
    ExpandedWrap disabled
      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
    ExpandedWrap disabled
      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
    ExpandedWrap disabled
      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
    ExpandedWrap disabled
      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< class Iter >, который работает точно также, как 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. Также, возможность выполнения атомарных операций(необходимо для синхронизации - реализации спин-локов)


    P.S. Обсуждение упомянутых фич, а также, изложение информации о неупомянутых фичах очень даже приветствуется :wub:



    remark: Добавлена ссылка на пост с продолжением: Новый стандарт C++. C++09 (сообщение #1601275)(стандартная библиотека)
    remark: Добавлена ссылка на пост с продолжением: Новый стандарт C++: C++09 (сообщение #1602819)(чего не будет в С++09)
    remark: Добавлена ссылка на пост с продолжением: TR1. Technical Report on C++ Library Extensions.
    remark: Добавлена ссылка на пост с продолжением: Trip Report: February/March 2008 ISO C++ Standards Meeting
    Сообщение отредактировано: JoeUser -
    If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
    © George Bernard Shaw
      Целая статья - огромная работа! :lol: Молодец.
      Щас буду вникать. Спасибо за перевод. 8-)
        С одной стороны эти изменения полезны, с другой усложняют и без того непростой язык. Отсюда следует, что должен появиться более простой язык, который станет самым популярным. Это не Java и не C#. Что касается описанных изменений, мне больше всего понравились Delegating Constructors.
        Мой сайт - www.prografix.narod.ru
          Цитата prografix @
          С одной стороны эти изменения полезны, с другой усложняют и без того непростой язык.

          Чуешь зависимость: "Язык усложняется - его использование упрощается"?

          Цитата
          Отсюда следует, что должен появиться более простой язык, который станет самым популярным.

          Silver bullshitet ?
            prografix, имхо здесь из усложнений только rvalue-references и то из-за того, что мозг ещё не освоился со всеми ньансами и не совсем понятно чего когда будет происходить... Но это только вопрос времени и мозг освоится так же быстро, как это было когда "появились" lvalue-references(в Си их же не было)... Всё остальное только упрощает код. Взять те же variadic templates. Если сейчас, я как огня боюсь залезать в бустовые хэдеры и пытаться одуплить реализацию bind, то, потом(с введением соответствующей фичи) - это будет так же просто, как одуплить реализацию вектора. В proposal'е была даже "примерная" реализация bind и, как ни странно, я всё понял :)

            Цитата Hryak @
            Silver bullshitet ?
            эт че?

            Добавлено
            psx, да ты не торопись - разберись для начала с текущей реализацией языка ;)
            If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
            © George Bernard Shaw
              Кстати, есть небольшая презенташка о состоянии готовящегося стандарта. Там описаны многие новые фичи языка.

              Добавлено
              Еще также подумывают про введение сборки мусора и облегчение создания динамически загружаемых модулей.
                mo3r, сборка мусора будет, но ничего, кроме самого факта я к сожалению не нашёл.
                Модулей в C++09 не будет. Скорее всего сделают отдельным TR. А может и до следующего стандарта отложат.
                If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
                © George Bernard Shaw
                  archimed7592 а чего, boost стандартом так и не станет пока?
                    archimed7592, Спасибо за статью! Очень понравилось.

                    Только вот не понял две вещи: :wall: :wall:

                    1. Raw String Literals
                    2. Prohibited access specifier

                    Обьясните поподробнее плз...

                    Добавлено
                    Ув. Модераторы, Может прибьете к потолку?
                      Цитата Xenon_Sk @
                      archimed7592 а чего, boost стандартом так и не станет пока?

                      Весь - нет.
                      Вещи, которые хорошо продуманы и проверены временем включаются в стандартную библиотеку(см. пункт "Перешло из boost").

                      Добавлено
                      Цитата Gunnar @
                      1. Raw String Literals
                      К примеру работаешь ты с регулярными выражениями.
                      Вот вполне себе простенькая регулярка:
                      ExpandedWrap disabled
                        \s+(\w+)\s+=\"((?:[^\"\\]|\\\"|\\n|\\t|...))*\"

                      в с++03 её придётся записать так:
                      ExpandedWrap disabled
                        char *rx = "\\s+(\\w+)\\s+=\\\"((?:[^\\\"\\\\]|\\\\\\\"|\\\\n|\\\\t|...))*\\\"";

                      в с++09 можно будет записать так:
                      ExpandedWrap disabled
                        char *rx = R"[\s+(\w+)\s+=\"((?:[^\"\\]|\\\"|\\n|\\t|...))*\"]";


                      Добавлено
                      Цитата Gunnar @
                      2. Prohibited access specifier

                      к примеру, все классы, расчитанные на динамическое использование запрещают копирование своих экземпляров
                      ExpandedWrap disabled
                        class I
                        {
                        private: // запрещаем
                            I(const I &);
                            I& operator =(const I &);
                        public:
                            // ...
                            void foo(const I &);
                        };
                         
                         
                        void I::foo(const I &a)
                        {
                            I b = a; // но запрет работает только для ф-ций не членов и не друзей.
                            // здесь линкер ругнётся
                            // и, не дай Б-г, кто-нибудь(ваш коллега, к примеру) додумается реализовать конструктор копирования - тогда не спасёт даже линкер
                        }

                      В С++09 добавили такой спецификатор доступа, который делает запрет даже ф-циям членам.
                      ExpandedWrap disabled
                        class I
                        {
                        prohibited: // запрещаем
                            I(const I &);
                            I& operator =(const I &);
                        public:
                            // ...
                            void foo(const I &);
                        };
                         
                         
                        void I::foo(const I &a)
                        {
                            I b = a; // запрет работает даже для ф-ций членов - compile-time error
                        }
                      If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
                      © George Bernard Shaw
                        archimed7592, все понял... И как я сам не допер? :blink: Все ж так просто.

                        Да новые возможности впечатляют. Не все еще вкурил окончательно, но это вопрос времени.



                        Но вот сэтим они конечно отожгли. Паскалюгой попахивает (или бейсиком??) :whistle:

                        Цитата archimed7592 @
                        Range-based for-loop

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

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


                        Ну и сборщик мусора на мой взгляд - лишний. Был один язык лишенный этого греха, и тот сдался.
                        Сообщение отредактировано: Gunnar -
                          Цитата Gunnar @
                          Паскалюгой попахивает (или бейсиком??) :whistle:
                          foreach - очень полезная фича. На данный момент либо используется std::for_each в связке с boost::lambda, либо кривоватый BOOST_FOREACH. Если это так часто используется, то почему бы не включить в стандарт поддержку на уровне языка?


                          Цитата Gunnar @
                          Ну и сборщик мусора на мой взгляд - лишний. Был один язык лишенный этого греха, и тот сдался.

                          Нет. Сборщик мусора будет исключительно опциональной фичей. Т.е. по умолчанию программа не будет знать ни о каком сборщике, а для того, чтобы пользоваться им придётся делать некоторые телодвижения. Скажу лишь, что в Symantec не дураки сидят(а именно они и занимаются добавлением GC в стандарт) и судя по их презенташкам(да и по логике вообще) сборка мусора должна только увеличить производительность в некоторого рода приложениях.
                          If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
                          © George Bernard Shaw
                            archimed7592 а где презентации поглядеть можно?
                              Xenon_Sk,
                              Programmer Directed GC for C++
                              Transparent Garbage Collection for C++

                              Сейчас наткнулся на ещё кое-какие документы про GC, может попозже обзорчик GC напишу.
                              If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
                              © George Bernard Shaw
                                Ага, молитесь ещё, чтоб всё это поддерживалось новыми компиляторами :D А то глядишь – к великолепной поддержке template export ещё много чего добавится :lol:

                                Цитата
                                ExpandedWrap disabled
                                  string s3 = static_cast<string &&>(s1); // move from s1 to s2

                                Я на данный момент реализую это примерно так:

                                ExpandedWrap disabled
                                  struct A
                                  {
                                      typedef const std::nothrow_t &quick_move;
                                      // ...
                                      A(const A &); // copy-constructor
                                      A(A &, quick_move); // move-constructor
                                      A &lvalue() { return (*this); }
                                  };
                                   
                                  A GetA();
                                   
                                  void f()
                                  {
                                      A a1(/* ... */);
                                      A a2 = a1; // construct a2 as a1 copy
                                      A a3(a1, std::nothrow); // move from a1 to a3
                                      A a4(GetA().lvalue(), std::nothrow); // move from temporary to a4
                                  }

                                Раньше я создавал move-конструкторы с передачей указателя, но Yak уговорил меня этого не делать :-)

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

                                Я вот только одной вещи пока не могу понять. Сейчас можно обернуть такой вызов в sizeof, и тогда никакого undefined behavior нет. Но будет ли такое работать в компиляторах с поддержкой C++09?

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

                                Лучше б они для результата встроенного оператора –>* тип ввели.
                                Сообщение отредактировано: Unreal Man -
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (74) [1] 2 3 ...  73 74


                                Рейтинг@Mail.ru
                                [ Script Execution time: 0,2700 ]   [ 17 queries used ]   [ Generated: 21.10.17, 22:51 GMT ]