Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум на Исходниках.RU > C/C++: Общие вопросы > Текущий Стандарт С++ и перспективы его развития |
Автор: archimed7592 11.06.07, 23:42 |
К октябрю 2007 года комитет запланировал публикацию законченного черновика стандарта C++09(который будет доступен публике для рассмотрения и критики). В октябре 2008 комитет внесёт окончательные коррективы в стандарт и, наконец, на 2009 год запланированна публикация нового стандарта "ISO/IEC 14883(2009): Programming Language C++". Надеюсь, не мне одному интересно, что же ожидает нас в новом С++. Потому, проштудировав документы, доступные обычным смертным на сайте open-std.org, я сделал маленький обзорчик ожидаемых вкусностей, которые готовит нам новый стандарт. Итак, в кратце, крупные нововведения следующие: Примечание: имеется так же обзор того, чего НЕ будет в С++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) взяли следующие критерии: Вот простейший пример: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> Всё бы хорошо, но нельзя сделать вызов f(1, 2, 3).template < class T1, class T2, class T3> void f(T1 &a1, T2 &a2, T3 &a3) { g(a1, a2, a3); } <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> Можно сделать вызов f(1, 2, 3), но, если g хотя бы для одного из параметров берёт неконстантную ссылку, то - облом.template < class T1, class T2, class T3> void f(const T1 &a1, const T2 &a2, const T3 &a3) { g(a1, a2, a3); } <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> Для перегруженного варианта всё отлично, кроме 3-го пункта, а именно, при росте числа параметров N, кол-во ф-ций, которые придётся написать, равное 2N, будет расти совсем нелинейно.template<class A1> void f(A1 & a1) { g(a1); } template<class A1> void f(A1 const & a1) { g(a1); } Короче говоря, текущий стандарт решить эту проблему не позволяет. Move semantics С++ - язык, построенный на семантике копирования(copy semantics). Что такое семантика перемещения(move semantics)? Хороший пример - std::auto_ptr. Его конструктор копирования берёт неконстантную ссылку и перемещает хранимую в исходном объекте сущность в новый объект(тем самым избегая глубокого копирования). Но, несмотря на то, что конструктор копирования auto_ptr берёт неконстантную ссылку, его суть не в том, чтобы изменить объект, а в том, чтобы переместить к себе его содержимое. Так же, семантика перемещения не помешала бы строкам. Вообразим, что строки у нас без подсчёта ссылок. Теперь вообразим, сколько ресурсов будет затрачено на вычисление такого выражения: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> string s = string("123")+"234"+"567"+"678"+"789"; будет создано как минимум 5 временных объектов и потом ещё произойдёт глубокое копирование результирующей строки в s(если нету подсчёта ссылок). А теперь, вообразим, как было бы прекрасно, если бы конструктор копирования умел бы отличать какой объект ему подсунули - временный или нет. Действительно, о временных объектах можно не волноваться и с чистой совестью "забирать" у них выделеный ими буфер, без необходимости глубокого копирования. К слову, эту проблему можно решить текущими возможностями языка, но очень уж некрасиво... Что же нам предлагает новый стандарт? А предлагает он следующее: ввести новый тип ссылок - rvalue reference. Синтаксис: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 т. е. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> return val; <=> return static_cast<ret_T &&>(val); Т.о. можно избежать глубокого копирования и ограничиться только лишь перемещением из возвращающей ф-ции в вызвавшую(при наличии соответствующего конструктора). Forwarding problem решается теперь следующим образом: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 обеспечивается следующим образом: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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, можно сделать каст, запросив необходимое поведение следующим образом: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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'ом этой проблемы как правило является следующая конструкция: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template < class T > struct MyVector { typedef std::vector< T, MyAllocator< T > > type; }; MyVector< int >::type vec; // не очень красивая запись Вторая же проблема выражается в том, что при использовании вышеобозначенного workaround'а перестаёт работать вывод шаблонных параметров. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 Алиасы позволяют решить обе проблемы. Алиасы представляют из себя объявления. Они не определяют новых типов. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 от реализации всех возможных вариаций типа <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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(...); И позволяет сделать шаблон, принимающий переменное количество шаблонных параметров: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template < class R, class... Args> // здесь троеточие - это синтаксический элемент R f(Args... args) { return g(args...); // вызываем g, передавая ей все аргументы. } Как к типам(Args), так и к экземплярам этих типов(args) можно применять разные операторы. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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...: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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), который будет приспосабливать данный тип к заданной концепции. Концепциями можно защитить не весь класс, а только некоторые его методы. Также, можно разработать несколько версий алгоритма эффективных для той или иной концепции и перегрузить его так, что будет выбран наиболее подходящий алгоритм. Синтаксис концепций интуитивно понятен и поясню я только некоторые моменты. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // вот так определяются концепции 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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# практикуется такое: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> f(new char[] {'1', 'a', '-'}); В С++09 предполагается нечто подобное(только без new ). Теперь можно будет написать <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> std::vector< int > v = { 1, 2, 3, 4, 5 }; Как написать класс, чтобы его можно было вот так инициализировать? <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> #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. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <typename T> struct Check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; Расширенная функциональность sizeof <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct C { some_type m; // ... }; const std::size_t sz = sizeof(C::m); // C++03 - error, C++09 - ok Delegating Constructors <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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. Достаточно интересная штука... настолько же, насколько и опасная, имхо... <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> std::vector<std::set<int>> v; // C++03 - ill-formed, C++09 - well-formed Range-based for-loop <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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__ <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 - новое ключевое слово. Суть нововведения в том, что теперь, например, можно как размерность массива использовать результат, возвращенный ф-цией. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // новые ключевые слова: 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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. Обсуждение упомянутых фич, а также, изложение информации о неупомянутых фичах очень даже приветствуется 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 |
Автор: psx 12.06.07, 04:03 |
Целая статья - огромная работа! Молодец. Щас буду вникать. Спасибо за перевод. |
Автор: prografix 12.06.07, 08:42 |
С одной стороны эти изменения полезны, с другой усложняют и без того непростой язык. Отсюда следует, что должен появиться более простой язык, который станет самым популярным. Это не Java и не C#. Что касается описанных изменений, мне больше всего понравились Delegating Constructors. |
Автор: Hryak 12.06.07, 09:14 |
Цитата prografix @ С одной стороны эти изменения полезны, с другой усложняют и без того непростой язык. Чуешь зависимость: "Язык усложняется - его использование упрощается"? Цитата Отсюда следует, что должен появиться более простой язык, который станет самым популярным. Silver bull |
Автор: archimed7592 12.06.07, 10:13 |
prografix, имхо здесь из усложнений только rvalue-references и то из-за того, что мозг ещё не освоился со всеми ньансами и не совсем понятно чего когда будет происходить... Но это только вопрос времени и мозг освоится так же быстро, как это было когда "появились" lvalue-references(в Си их же не было)... Всё остальное только упрощает код. Взять те же variadic templates. Если сейчас, я как огня боюсь залезать в бустовые хэдеры и пытаться одуплить реализацию bind, то, потом(с введением соответствующей фичи) - это будет так же просто, как одуплить реализацию вектора. В proposal'е была даже "примерная" реализация bind и, как ни странно, я всё понял эт че? Добавлено psx, да ты не торопись - разберись для начала с текущей реализацией языка |
Автор: mo3r 12.06.07, 11:18 |
Кстати, есть небольшая презенташка о состоянии готовящегося стандарта. Там описаны многие новые фичи языка. Добавлено Еще также подумывают про введение сборки мусора и облегчение создания динамически загружаемых модулей. |
Автор: archimed7592 12.06.07, 11:32 |
mo3r, сборка мусора будет, но ничего, кроме самого факта я к сожалению не нашёл. Модулей в C++09 не будет. Скорее всего сделают отдельным TR. А может и до следующего стандарта отложат. |
Автор: Xenon_Sk 12.06.07, 11:59 |
archimed7592 а чего, boost стандартом так и не станет пока? |
Автор: Gunnar 12.06.07, 12:45 |
archimed7592, Спасибо за статью! Очень понравилось. Только вот не понял две вещи: 1. Raw String Literals 2. Prohibited access specifier Обьясните поподробнее плз... Добавлено Ув. Модераторы, Может прибьете к потолку? |
Автор: archimed7592 12.06.07, 12:52 |
Весь - нет. Вещи, которые хорошо продуманы и проверены временем включаются в стандартную библиотеку(см. пункт "Перешло из boost"). Добавлено К примеру работаешь ты с регулярными выражениями. Вот вполне себе простенькая регулярка: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> \s+(\w+)\s+=\"((?:[^\"\\]|\\\"|\\n|\\t|...))*\" в с++03 её придётся записать так: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> char *rx = "\\s+(\\w+)\\s+=\\\"((?:[^\\\"\\\\]|\\\\\\\"|\\\\n|\\\\t|...))*\\\""; в с++09 можно будет записать так: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> char *rx = R"[\s+(\w+)\s+=\"((?:[^\"\\]|\\\"|\\n|\\t|...))*\"]"; Добавлено к примеру, все классы, расчитанные на динамическое использование запрещают копирование своих экземпляров <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 добавили такой спецификатор доступа, который делает запрет даже ф-циям членам. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 } |
Автор: Gunnar 12.06.07, 13:12 |
archimed7592, все понял... И как я сам не допер? Все ж так просто. Да новые возможности впечатляют. Не все еще вкурил окончательно, но это вопрос времени. Но вот сэтим они конечно отожгли. Паскалюгой попахивает (или бейсиком??) Цитата 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; Ну и сборщик мусора на мой взгляд - лишний. Был один язык лишенный этого греха, и тот сдался. |
Автор: archimed7592 12.06.07, 13:21 |
foreach - очень полезная фича. На данный момент либо используется std::for_each в связке с boost::lambda, либо кривоватый BOOST_FOREACH. Если это так часто используется, то почему бы не включить в стандарт поддержку на уровне языка? Цитата Gunnar @ Ну и сборщик мусора на мой взгляд - лишний. Был один язык лишенный этого греха, и тот сдался. Нет. Сборщик мусора будет исключительно опциональной фичей. Т.е. по умолчанию программа не будет знать ни о каком сборщике, а для того, чтобы пользоваться им придётся делать некоторые телодвижения. Скажу лишь, что в Symantec не дураки сидят(а именно они и занимаются добавлением GC в стандарт) и судя по их презенташкам(да и по логике вообще) сборка мусора должна только увеличить производительность в некоторого рода приложениях. |
Автор: Xenon_Sk 12.06.07, 13:23 |
archimed7592 а где презентации поглядеть можно? |
Автор: archimed7592 12.06.07, 13:27 |
Xenon_Sk, Programmer Directed GC for C++ Transparent Garbage Collection for C++ Сейчас наткнулся на ещё кое-какие документы про GC, может попозже обзорчик GC напишу. |
Автор: Unreal Man 12.06.07, 13:56 |
Ага, молитесь ещё, чтоб всё это поддерживалось новыми компиляторами А то глядишь – к великолепной поддержке template export ещё много чего добавится Цитата <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> string s3 = static_cast<string &&>(s1); // move from s1 to s2 Я на данный момент реализую это примерно так: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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<> Лучше б они для результата встроенного оператора –>* тип ввели. |
Автор: archimed7592 12.06.07, 14:13 |
Цитата Unreal Man @ Не совсем понял, как sizeof может помочь в передаче не-POD'а в элипсис(в printf, к примеру) так, чтобы это не повлекло UB. Приведи пример.Сейчас можно обернуть такой вызов в sizeof, и тогда никакого undefined behavior нет. Цитата Unreal Man @ С export template связаны некоторые проблемы реализации. Что же касается выше обозначенных фич - никаких проблем при реализации возникнуть не должно. К слову уже сейчас можно скачать расширения g++ для поддержки variadic templates, concepts. расширение vs-8.0 для поддержки template aliases и т.д.Ага, молитесь ещё, чтоб всё это поддерживалось новыми компиляторами А то глядишь – к великолепной поддержке template export ещё много чего добавится сам то понимаешь, что это не совсем разумное решение будет? в изначальном документе, предлагающем move semantics было озвучено, что вроде как реализовать это можно и без rvalue-references чисто библиотечным путём: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> Не знаю, насколько это всё будет работать, но, в первом приближение - вполне себе будет работать template <class T> class move_t { const T& t; public: move_t(const T& a) : t(a) {} operator T&(){ return t; /* тут видимо забыли const_cast, но я привожу дословно :) */ } }; struct A { A(const A &); // copy ctor A(move_t<A>); // move ctor }; И тем не менее, поддержка на уровне языка мне нравится больше |
Автор: mo3r 12.06.07, 14:29 |
Цитата archimed7592 @ Модулей в C++09 не будет. Скорее всего сделают отдельным TR. А может и до следующего стандарта отложат. Похоже, что да... И так фич новых много. Цитата Gunnar @ Ну и сборщик мусора на мой взгляд - лишний. Был один язык лишенный этого греха, и тот сдался. Сборщик мусора полезен А проблема сборщиков во многих языков в том, что он неотключаем и некоторые вещи (типа RAII) с ним несовместимы. Здесь же планируется опциональный (т.е., указывается, к чему его надо применять, а к чему — нет). Поэтому комбинируются лучшие стороны — если нужен GC, он просто включается, а если не нужен, то он не мешает. Цитата Unreal Man @ Ага, молитесь ещё, чтоб всё это поддерживалось новыми компиляторами А то глядишь – к великолепной поддержке template export ещё много чего добавится Цитата archimed7592 @ К слову уже сейчас можно скачать расширения g++ для поддержки variadic templates, concepts. В g++ (версии 4.3 и в CVS HEAD) (и comeau) уже поддерживается часть новых фишек. Обещают добавлять туда поддержку фич по мере продвижения процесса голосования по ним. Так что к 2009 году наверняка будет по крайней мере два компилятора, обладающих хорошей поддержкой. msvc тоже наверняка будет поддерживать. |
Автор: Unreal Man 12.06.07, 14:36 |
Кстати, по части шаблонов в C++ нередко не хватает чего-то вроде static if (см. digitalmars.D.learn - static assert / static if) |
Автор: archimed7592 12.06.07, 14:43 |
Точно тебе говорю . Со слов Саттера(да и комитета в общем) в С++09 этого не будет. во-первых, есть #if #else #endif, во-вторых, озвученная в указанной тобой статье проблема решается с помощью описанных в первом посте "Generalized Constant Expressions" |
Автор: Unreal Man 12.06.07, 14:46 |
Цитата archimed7592 @ Не совсем понял, как sizeof может помочь в передаче не-POD'а в элипсис(в printf, к примеру) Не, тут другое дело. Иногда (у меня так почти всегда) эллипсис применяется для игр с перегрузкой функций, где результат перегрузки становится извествен благодаря sizeof (то, что внутри sizeof, не вычисляется в run-time). Пример можешь посмотреть здесь. Вот будет ли такое работать согласно новому стандарту? Это почему же? Добавлено Ну, эт совсем не то. Препроцессор тем и плох, что он препроцессор С шаблонами его не поюзаешь. Цитата archimed7592 @ озвученная в указанной тобой статье проблема решается с помощью описанных в первом посте "Generalized Constant Expressions" Покажи, каким образом. Добавлено Проблема с выбором у меня часто такая: нужно в зависимости от некоторого условия выбрать их двух или более шаблонных классов один в качестве typedef-а некоего типа, причём инстанцироваться должен только выбранный тип. Реализация такого выбора в C++ – геморрой редкостный. |
Автор: archimed7592 12.06.07, 15:04 |
Ну, раз другое дело... то и разговор другой и о другом Будет. Почти всё, что работало до этого работать будет. По указанной тобой ссылке я не нашёл передачи не-POD'а в элипсис. Потому что это уже будет специальный тип в который будет пробинден this. А зачем? Много ньюансов и подводных камней. И опять же, зачем? Кому и для чего это нужно? В стандарт включают вещи, которые кому-то и зачем-то нужны. И, в конце концов, для этого есть bind или mem_fn. Считай, что результат, возвращённый mem_fn является тем самым типом <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> constexpr int fact(int n) { if (n > 0) return fact(n - 1); else return 1; } double array[fact(5)]; // C++09 well-formed Добавлено Цитата Unreal Man @ эээ... либо я чего-то не понял, либо:Проблема с выбором у меня часто такая: нужно в зависимости от некоторого условия выбрать их двух или более шаблонных классов один в качестве typedef-а некоего типа, причём инстанцироваться должен только выбранный тип. Реализация такого выбора в C++ – геморрой редкостный. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template < bool Condition, class TrueType, class FalseType > struct select; template < class TrueType, class FalseType > struct select< true, TrueType, FalseType > { typedef TrueType type; }; template < class TrueType, class FalseType > struct select< false, TrueType, FalseType > { typedef FalseType type; }; template < int N > struct A { typedef typename select< (N > 0), vector< bool >, bitset< 256 > >::type container_t; // ... }; Добавлено Прочитал все доступные на сайте комитета документы по GC. Пока толком не понял как коллектор будет реализовываться. Чего-то они там перемудрили со "сканированием памяти на предмет поиска указателей". Нафик сканировать массив char * и искать в нём указатели? |
Автор: trainer 13.06.07, 04:28 |
Это явно под влиянием Java. Там это выглядит практически аналогично. С одной стороны это удобно, с другой стороны это будет, видимо, первый случай высокоуровневого примитива в языке. |
Автор: Unreal Man 13.06.07, 10:08 |
Я показал смысл использования эллипсиса. Передача не-POD-объекта может быть, например, при проверке конвертируемости объекта одного типа в объект другого типа (у Александреску это, вроде, было). Цитата archimed7592 @ Потому что это уже будет специальный тип в который будет пробинден this. А зачем? Много ньюансов и подводных камней. Каких подводных камней? Это к вопросу «а зачем нужно использовать операторы?» Ну да, а ещё есть, например, std::plus: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> int x, y; ... // ну зачем же тут писать x+y, когда есть такой красивый способ? int result = std::plus<int>()(x, y); В том-то и дело, что это «либо» годится далеко не всегда. Недостаток этого способа в том, что он требует инстацирования обоих выбираемых типов, что иногда неприемлемо: тип, остающийся невыбранным, в ряде случаев не может быть успешно инстанцирован, из-за чего ты будешь хватать ошибки компиляции. Для реализации такого выбора приходится писать вспомогательный шаблон – на каждый случай свой. |
Автор: archimed7592 13.06.07, 10:57 |
implicitly инстанцирований, если не ошибаюсь. Не могу придумать такого клинического случая, чтобы implicitly инстанцирование упало. Хоть с enable_if извращайся... |
Автор: archimed7592 13.06.07, 23:55 |
Стандартная библиотека C++09 Более подробный обзор библиотечных изменений. numeric_limits::max_digits10 digits10 означает(как и в C++03) кол-во десятичных цифр, которые не потеряют в точности после некоторых вычислений. max_digits10 означает кол-во десятичных цифр, которые тип вообще способен хранить. iostream manipulator: defaultfloat Манимулятор делает unsetf(ios_base::floatfield). Т.е. убирает эффект ранее применённых манипуляторов fixed или scientific. Может кому-то это и понадобится . Скорее новичкам. Усовершенствованное использование const_iterator Во-первых, с введением auto, следующий код будет использовать iterator, даже когда желаемым является использование const_iterator. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> vector< int > v; for (auto it = v.begin(); i != v.end(); ++i) { /* ... */ } // такой workaround не подходит в общем случае // т.к. iterator и const_iterator по идее имеют право быть // совершенно разными и несовместимыми типами for (const auto it = v.begin(); i != v.end(); ++i) { /* ... */ } Также, в практике очень часто встречаются случаи, когда желаемо использование именно константного итератора в целях безопасности. К примеру, в ФП для этого приходится применять обёртки типа boost::cref или boost::lambda::constant_ref. Пример из соответствующего документа(блин, как будет proposal по русски? ) <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> void reset( double & d ) { d = 0.0; } void resee( double d ) { cout << ' ' << d; } vector<double> v; // распечатать v ... for_each( v.begin(), v.end(), reset ); // oops: хотели написать resee В связи с этим для всех STL-совместимых контейнеров ввели новые ф-ции <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> const_iterator cbegin() const; const_iterator cend() const; // для реверсивных контейнеров const_reverse_iterator crbegin() const; const_reverse_iterator crend() const; Теперь можно со спокойной душой писать auto it = v.cbegin() и не опасаться случайного изменения данных. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> void reset( double & d ) { d = 0.0; } void resee( double d ) { cout << ' ' << d; } vector<double> v; // распечатать v ... for_each( v.cbegin(), v.cend(), reset ); // oops: compile-time error Заметьте тенденцию, как на С++ становится всё проще и проще писать всё более и более надёжный код. Чем дальше залезаю, тем больше понимаю, что С++ идеален и ни один холивар не докажет мне обратного next, prior Аналоги std::advance, но в отличие от advance возвращают изменённый итератор(точнее новый, равный изменённому). is_sorted, is_heap Помошники в собственных реализациях алгоритмов сортировки. Diagnostics Enhancements В связи с тем, что системно-зависимые телодвижения сообщают об ошибках немного иначе, чем принято в С++, а именно, ошибку описывает некое магическое число, добавили новых типов, для обёртывания этих чисел в исключения. Этот пункт рассчитывался для включения в TR2 т.к. там появятся FileSystem и Networking, но, т.к. в С++09 появились потоки, которые тоже порой "ошибаются", решили включить этот документ в стандарт. Итак, теперь errno.h является почти полностью соответствующим POSIX. В нём теперь определены макросы E2BIG, EACCESS, и т.д. Добавлен хэдер <system_error> определяющий следующие типы(и переменные): <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> class system_error; class error_code; class error_category; extern const error_category& posix_category; extern const error_category& native_category; enum posix_errno { file_too_large, file_exists, // ... }; system_error - наследник runtime_error. Собственно говоря, потоковая, файловая и сетевая библиотеки будут бросать исключения именно этого(или унаследованного от этого) типа. error_code - обёрточка для "магического числа". error_category и иже с ним - определяет является ли ошибка posix-совместимая или же "родная" для системы. posix_errno - перечисление, члены которого являются эквивалентами соответствующих ошибок EXXXX. minmax, minmax_element minmax(a, b) - возвращает упорядоченную пару значений, эквивалентную make_pair(min(a,b), max(a,b)). minmax_element(first, last) - возвращает упорядоченную пару итераторов make_pair(min_element(first, last), max_element(first, last))(минимальный и максимальный в последовательности). И две соответствующие перегрузки для использования с заданным предикатом(вместо используемого по умолчанию operator<). long long goes to the Library В связи с оффициальным статусом "новых" интегральных типов `long long` и `unsigned long long` стандартная библиотека обзавелась возможностями работы с этим типом(numeric_limits, hash, iostreams). Unicode-строки В связи с введением двух новых типов - char16_t и char32_t(а также литералов u"..." и U"..."), сделали поддержку UTF-16 и UTF-32 строк. Рассматривается возможность добавления несовместимого с basic_string класса для UTF-8(литерал E"..."). UTF-16 в большинстве случаев представляет одну букву одним символом, а суррогаты(в случае их неправильной интерпретации) могут повредить только одну букву(рядом с которой они находятся). UTF-32 во всех случаях представляет одну букву одним символом. В связи с этим для представления UTF-16/32-строк вполне подходит basic_string. Добавлены специализации <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> char_traits<char16_t> char_traits<char32_t> basic_string<char16_t> = u16string basic_string<char32_t> = u32string hash<char16_t> hash<char32_t> hash<u16string> hash<u32string> Незначительные изменения type_traits Исправлено около 40 проблем. Добавлены средства для lvalue/rvalue-references. Немного модифицированны характеристики конструкторов(в связи с облегчением ограничений на POD'ы и введением trivial-type и standard-layout-type). Random Number Generation Предложений улучшить средства стандартной библиотеки генерирования псевдослучайных чисел было великое множество. Тот же TR1 включает в себя некоторые. Всё это было пересмотренно, переработанно обобщено и, наконец то, включенно в стандарт. Те кто знаком с boost::random могут не читать - поменялись только названия(ну и, может быть, добавлены новые генераторы). Имеет смысл распределения. Представляет из себя функтор, который на вход берёт объект, отвечающий концепции Uniform random number generator, на выходы даёт распределение относительно параметра p(который задаётся при конструкции распределения или как второй аргумент функтора). Включённых в стандарт распределений(отвечающих концепции) много, список приводить смысла, думаю, не имеет. Адаптация стандартной библиотеки к rvalue-references Введены концепции MoveConstructible и MoveAssignable. Их смысл, думаю, должен быть понятен auto_ptr объявлен устаревшим(deprecated), а на его замену пришёл unique_ptr. unique_ptr отличается от auto_ptr тем, что у него есть возможность задавать deleter. Также, он разработан в расчёте на семантику перемещения и его конструктор копирования и копирующий оператор присваивания запрещены(недоступны). Есть две частичные специализации для массивов переменной длины и для массивов фиксированной длины. Как уже было упомянуто в первом посте, для rvalue-ссылок сделаны ф-ции помощники move и fwd. Также добавились алгоритмы move, move_backward, предназначенные для "разрушающего std::copy" К алгоритмам, которые изменяют последовательность путём перемещения/переставления элементов(sort, merge, etc.) добавлены требования на тип элемента: помимо того, что он должен был быть Swappable, он теперь ещё должен быть MoveConstructible и MoveAssignable. Использовать unique_ptr теперь можно намного более надёжно, чем это было с auto_ptr. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> Т.е. теперь мы должны ясно выразить мысль, что мы хотим "отдать" объект(относится только к lvalue(-reference)).void f(unique_ptr< int >); unique_ptr< int > up1(new int(7)); unique_ptr< int > up2 = up1; // compile-time error unique_ptr< int > up3 = move(up1); // ok f(up3); // compile-time error f(move(up3)); // ok unique_ptr< int[] > uparr(new int[256]); // за счёт специализации выберется правильный deleter(delete[] ptr). unique_ptr< IInterface > f2() { class Realization : public IInterface { /* ... */ }; // ... if (/* ... */) return unique_ptr< IInterface >(new Realization(/* ... */)); // ok unique_ptr< IInterface > up(new Realization(/* ... */)); // ... return up; // compile-time error return move(up); // ok } <iostream> - header dependency Наконец то . Теперь хэдер <iostream> подключает <ios>, <streambuf>, <istream> и <ostream>. Вам возможно смешно, но, на самом деле, по стандарту(а мы говорим именно о нём ), подключив только <iostream> нельзя использовать ни std::endl, ни операторы << и >>(и это только один из примеров). Т.е. по стандарту многие программы могут просто не компилироваться. Зная это я всегда писал #include <ostream> и #include <istream> и лично меня это телодвижение немного напрягало. Также подумывают о создании отдельного хэдера <std>, включающего всю стандартную библиотеку(актуально для очень маленьких программ или проектов в которых используются precompiled headers). enable_if, conditional "Новые" шаблончики. Давно используются сообществом и пришли из boost. enable_if предназначен для манипулирования принципом SFINAE на основе некоторого статического условия. conditional позволяет выбрать один из двух типов на основе некоторого статического условия. Внедрение std::string В стандарте было около 20 мест, где использовался тип char * для передачи строки. Везде добавили перегруженные эквиваленты для std::string. В основном затронуты локализация и fstreams.(ifstream::open, к примеру). Yet another type-trait: decay <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template < class T > struct decay { typedef /* см.ниже */ type; }; // Если T - массив, т.е. T <=> U[] или U[N], то decay< T >::type есть U *. // Eсли T - фунция, т.е. T <=> R(A1, A2, ...), то decay< T >::type есть T *, т.е. указатель на ф-цию. Variadic Templates в стандартной библиотеке Как уже было упомянуто, в библиотеке появилось следующее: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <class... Types> class tuple; template<class Fn, class... Types> /* unspecified */ bind(Fn, Types...); template<class R, class Fn, class... Types> /* unspecified */ bind(Fn, Types...); template<class Function> class function; // undefined template<class R, class... ArgTypes> class function<R(ArgTypes...)>; tuple - во-первых, может использоваться как идиома "списки типов". Во-вторых, может использоваться как std::pair на произвольное кол-во типов(и элементов). bind - биндер из boost. function - обёртка обобщённого функтора(тоже из boost). TR1. Technical Report on C++ Library Extensions Ну и конечно же tr1. С теми или иными модификациями, он полностью включенн в стандарт. Почти все сущности перенесены из пространства имён std::tr1 в пространство имён std. Про содержание tr1 в следующий раз . Добавлено описание TR1. Здесь описаны(упомянуты) далеко не все на текущий момент нововведения и исправления в Стандартной Библиотеке. Обсуждение, дополнения и коррективы приветствуются. Всем спасибо за внимание. remark: добавленна ссылка на продолжение(TR1): TR1. Technical Report on C++ Library Extensions. Сообщения были разделены в тему "Грамматика C++" |
Автор: mo3r 14.06.07, 04:47 |
Предложение Цитата archimed7592 @ UTF-16 в большинстве случаев представляет одну букву одним символом, а суррогаты(в случае их неправильной интерпретации) могут повредить только одну букву(рядом с которой они находятся). UTF-32 во всех случаях представляет одну букву одним символом. В UTF-32 один endpoint кодируется фиксированным набором байтов. Но одна буква может занимать более одного endpoint'а. Цитата http://unicode.org/faq/char_combmark.html#7 Q: How should characters (particularly composite characters) be counted, for the purposes of length, substrings, positions in a string, etc. A: In general, there are 3 different ways to count characters. Each is illustrated with the following sample string. "a" + umlaut + greek_alpha + \uE0000. (the latter is a private use character) 1. Code Units: e.g. how many bytes are in the physical representation of the string. Example: In UTF-8, the sample has 9 bytes. [61 CC 88 CE B1 F3 A0 80 80] In UTF-16BE, it has 10 bytes. [00 61 03 08 03 B1 DB 40 DC 00] In UTF-32BE, it has 16 bytes. [00 00 00 61 00 00 03 08 00 00 03 B1 00 0E 00 00] 2. Codepoints: how may code points are in the string. The sample has 4 code points. This is equivalent to the UTF-32BE count divided by 4. 3. Graphemes: what end-users consider as characters. A default grapheme cluster is specified by the Unicode Standard 4.0, and is also in UTR #18 Regular Expressions at http://www.unicode.org/reports/tr18/. The choice of which one to use depends on the tradeoffs between efficiency and comprehension. For example, Java, Windows and ICU use #1 with UTF-16 for all low-level string operations, and then also supply layers above that provide for #2 and #3 boundaries when circumstances require them. This approach allows for efficient processing, with allowance for higher-level usage. However, for a very high level application, such as word-processing macros, graphemes alone will probably be sufficient. [MD] Добавлено Opaque typedef (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1891.pdf) Появятся новые виды typedef'ов, которые позволят создать новый тип, который ведет себя точно так же, как и какой-то другой, но между ними не будет неявного преобразования. Полезно, например, когда какой-то примитивный тип по всем свойствам подходит для описания чего-либо (например, координаты или физические величины или хэндлы объектов ОС), но неявные преобразования нежелательны. Пример: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> opaque typedef double X, Y, Z; // Cartesian 3D coordinate types opaque typedef double Rho, Theta, Phi; // polar 3D coordinate types class PhysicsVector { public: PhysicsVector(X, Y, Z); PhysicsVector(Rho, Theta, Phi); ... }; // PhysicsVector |
Автор: LuckLess 14.06.07, 06:35 |
Ура. Очень разд этой виче. Только не понял.. (может не очень внимательно читал...?) ссылка на ссылку как..? Опять запрещена? ведь T&& это rValue reference а не ссылка на ссылку.. (( Добавлено вообще имхо не лучшее обозначение. лучшеб там.. ну хотябы T^ rvalueRef; |
Автор: Unreal Man 14.06.07, 09:03 |
Не понимаю, к чему ты клонишь. Кстати, выбором типа проблема не ограничивается. Например, тебе нужно сделать swap для объектов двух неизвестных типов. Какие тут могут быть варианты? Кто-то может реализовать у своего класса метод с именем swap, кто-то другой – с именем Swap, ещё кто-то может вообще такой метод не реализовывать, тогда остаётся только вызвать std::swap. Вот примерная реализация функции, вызывающей нужный swap, которая могла бы получиться со static if: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <class T> void MakeSwap(T &a1, T &a2) { static if (CHECK_METHOD(swap, void (T &))) // реализацию макроса CHECK_METHOD скипаю a1.swap(a2); else if (CHECK_METHOD(Swap, void (T &))) a1.Swap(a2); else std::swap(a1, a2); } Насколько всё лаконично, просто и понятно. А теперь сравни вот с этим извращением <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <class T> void MakeSwapHelper(T &a1, T &a2, IntToType<0>) { a1.swap(a2); } template <class T> void MakeSwapHelper(T &a1, T &a2, IntToType<1>) { a1.Swap(a2); } template <class T> void MakeSwapHelper(T &a1, T &a2, IntToType<2>) { std::swap(a1, a2); } template <class T> void MakeSwap(T &a1, T &a2) { const int variant = CHECK_METHOD(swap, void (T &)) ? 0 : CHECK_METHOD(Swap, void (T &)) ? 1 : 2; MakeSwapHelper(a1, a2, IntToType<variant>()); } А при чём тут, собственно, enable_if? |
Автор: Gunnar 14.06.07, 09:41 |
Цитата Unreal Man @ Кто-то может реализовать у своего класса метод с именем swap, кто-то другой – с именем Swap, ещё кто-то может вообще такой метод не реализовывать Это к психиатру, однозначно. Если есть соглашения, им нужно следовать, если нет - их нужно принять. Если тип из 3-парти либы, к нему нужно написать адаптер, который реализует соглашения. Добавлено а если найдутся умники которые реализуют методы sWap, svap, SWaP, pomenyat_mestami, и.т.д. Ты их тоже в статик иф засунешь??? Бред! |
Автор: archimed7592 14.06.07, 09:49 |
когда-то была разрешена? ты наверное не понял, что && - интерпретируется как отдельный токен т.е. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> typedef int & rint; typedef rint & rint2; // rint2 <=> rint <=> int & и так было, если не ошибаюсь аж с C++98 typedef int && rrint; // rrint - не то же самое, что rint2 typedef rrint & rint3; // rint3 <=> int && & <=> int & - по одному из правил сворачиваем ссылку есть ещё такой момент, что T^ - используется в C++/CLI, а C++/CLI используется микрософтом, а в микрософте работает Герб Саттер, а он председатель комитета, если не ошибаюсь ещё есть момент, что C++/CLI тоже разрабатывался комитетом. |
Автор: mo3r 14.06.07, 10:10 |
Цитата Gunnar @ Это к психиатру, однозначно. Если есть соглашения, им нужно следовать, если нет - их нужно принять. Если тип из 3-парти либы, к нему нужно написать адаптер, который реализует соглашения. Одно из предназначений шаблонов — интеграция кода из разных библиотек написанных разными людьми в разное время. Так что вполне нормальная ситуация. А вообще, хотелось бы в языке видеть что-то наподобие Nemerle'вских макросов вместо программирования на шаблонах (например, см. http://rsdn.ru/article/nemerle/nemerleMacros.xml) (раз уж лисповские макросы не получится сделать). Это бы сильно упростило метапрограммирование. |
Автор: LuckLess 14.06.07, 10:52 |
Нет.. не была.. но я все надеялся что будет разрешена.. но видимо зря.. (( Добавлено Цитата archimed7592 @ есть ещё такой момент, что T^ - используется в C++/CLI, а C++/CLI используется микрософтом, Не вижу связи.. языки то разные.. какая разница что там чтото используется.. Да я понял.. просто хотел чтобы T&& было ссылкой на ссылку всеже.. и... если делать отдельный токен как && то надежда о ссылке на ссылку улетает.. ибо онаб выгладила как &&.. |
Автор: Gunnar 14.06.07, 11:03 |
Не совсем разные. C++/CLI - это надмножество С++. Т.е использование T^ в С++ неприемлемо. |
Автор: LuckLess 14.06.07, 11:06 |
Ту.. тогда уж это надмножество С++ стандарта 2003-го года, и в принципе может и не быть надмножеством 2009-го года.. Хотя я вообще не уверен что это может быть именно надмножеством.. как допускаются asm вставки в управляемый код?? но спорить не буду ибо с темой не знаком. ладно.. какие там еще значки есть.. T% rvalueRef; пусть так тогда.. |
Автор: Gunnar 14.06.07, 11:20 |
Ну дык будет новый стандарт C++/CLI "подогнанный" под С++ 2009 |
Автор: LuckLess 14.06.07, 11:28 |
Gunnar Есть ли asm вставки в C++/CLI ? Добавлено ну так пусть портят .Net всякими && а оставят нормальный С++ с нормальными значками. ну да ладно есть еще T$, T#, T%... |
Автор: archimed7592 14.06.07, 11:38 |
Не совсем понял... а как ты себе представляешь "ссылку на ссылку". Т.е. какой у неё будет смысл? в c++/cli допустимо всё, что допустимо в с++ плюс .net навороты. Уже занято тем же c++/cli Вроде да. Там нету отличия уравляемого кода от неуправляемого. По крайней мере на уровне языка. Твори что душе угодно |
Автор: LuckLess 14.06.07, 11:47 |
Цитата archimed7592 @ Не совсем понял... а как ты себе представляешь "ссылку на ссылку". Т.е. какой у неё будет смысл? Такойже как у ссылки. т.е. ссылка на ссылку на ссылку на ссылку тоже самое что просто ссылка. Зачем это? пример. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> class BigClass { public: BigClass (const BigClass&) //very very slooow copy { } BigClass () { } bool Func (int) const { std::cout << "Ы\n"; return false; } }; class LLClass { public: bool Func (BigClass&) const //workaround //bool Func (BigClass) const //no ref! copying BigClass! А если конструктор копирования вообще закрыт?? { std::cout << "Ы\n"; return false; } }; int main () { BigClass veryBigVariable; std::vector<LLClass> lotsOfBigClasses; std::for_each (lotsOfBigClasses.begin (), lotsOfBigClasses.end (), std::bind2nd (std::mem_fun_ref (&LLClass::Func), veryBigVariable));//error C2529: '_Right' : reference to reference is illegal } |
Автор: archimed7592 14.06.07, 11:49 |
Цитата LuckLess @ Такойже как у ссылки. т.е. ссылка на ссылку на ссылку на ссылку тоже самое что просто ссылка Эээ... так нет. Это ввели. Это и понимается под правилами сворачивания ссылок. |
Автор: LuckLess 14.06.07, 11:57 |
Цитата archimed7592 @ Эээ... так нет. Это ввели. Это и понимается под правилами сворачивания ссылок. Но как тогда обходится конфликт с &&.. ибо во время инстанциирования шаблона у меня получится T&& который будет означать ссылку на ссылку, а не ссылку на ravlue. |
Автор: archimed7592 14.06.07, 12:00 |
У тебя получится "T & &", а это не то же самое, что и "T &&". Опять повторяю, что "&&" и "& &" разные вещи. Аналогично как и "++" и "+ +". |
Автор: LuckLess 14.06.07, 12:06 |
т.е. для указателей я могу написать ** а для ссылок нада извращатся с "& &"? И если это изза того что гребанный C++/CLI есть на белом свете то я пойду отстреливать Билла. Добавлено T# хоть не занят эти дурацким языком? Если не занят то почему бы не использовать T#? И вообще.. что будет взятие адреса у T&&? не T* же? Этож нада будет новый тип опять... указатель на rvalue.. чтото типа нада сделать rvalue T& rvalueVar; //ссылка на rvalue rvalue T* rvalueVar; //указатель на ravlue Добавлено погоди.. неужели это будет тип T&&*? |
Автор: archimed7592 14.06.07, 12:12 |
Ты так можешь написать только потому, что такого токена как ** не существует и, соответственно, интерпретируется как два последовательных * Цитата LuckLess @ И если это изза того что гребанный C++/CLI есть на белом свете то я пойду отстреливать Билла. Да нет же. Не поэтому. Вот по текущему стандарту необходимо писать "set<set<int> >", а не "set<set<int>>". Ты же не пойдёшь отстреливать Кернигана за то, что он придумал ввести в язык побитовые сдвиги и токен ">>" интерпретируется именно как оператор сдвига, а не как две закрывающих скобки. |
Автор: LuckLess 14.06.07, 12:17 |
Правильно. Ссылка во многом похожа на указатель в плане "написания" типа. Почему бы токен ** тогда не придумать.. вот все охренеют.. Когда я вижу ** я знаю что тут указатель на указатель, и обсолютно логично смотреть на && как на ссылку на ссылку. Дохрена ведь разных значков есть, зачем использовать && мне непонятно.. T~, T`, T", T#, T:, T?, T.; еще думаю придумать можно.. запись T&& будет путать 100 процентно. Мое имхо что && в финальной версии не будет, ибо это бяка. Ключевое слово, или новый символ.. вот что должно быть. |
Автор: archimed7592 14.06.07, 12:19 |
Цитата LuckLess @ T# хоть не занят эти дурацким языком? Если не занят то почему бы не использовать T#? Да расслабься ты. Эти ссылки были предложены ещё в 2002 году и тогда, если не ошибаюсь и ^ и % были "свободны". Они и сейчас свободны. Просто, видимо, решили сделать синтаксис rvalue-ссылок похожим на синтаксис обычных(lvalue). Будет T *, означающая адрес ссылаемого объекта. Дабы не разводить лишнего флейма, прочитай пожалуйста ещё раз, зачем были введены эти ссылки. Можешь в оригинале(n1377). В двух словах: для того, чтобы отличать временные объекты от обычных, что может дать прирост производительности(при соответствующей поддержке со стороны реализации класса). Добавлено Цитата LuckLess @ Правильно. Ссылка во многом похожа на указатель в плане "написания" типа. Почему бы токен ** тогда не придумать.. вот все охренеют.. Когда я вижу ** я знаю что тут указатель на указатель, и обсолютно логично смотреть на && как на ссылку на ссылку. Дохрена ведь разных значков есть, зачем использовать && мне непонятно.. T~, T`, T", T#, T:, T?, T.; еще думаю придумать можно.. запись T&& будет путать 100 процентно. LuckLess, как тебе такой момент, что нельзя будет писать int & & x? Между прочим, если бы можно было, то путало бы это не меньше. Цитата LuckLess @ Ты не поверишь, но rvalue-ссылки уже включены в WP(рабочий черновик) и внедрены в туеву хучу мест стандарта(вся стандартная библиотека) и, поверь, никто не будет переделывать это на лад шапочек или процентиков.Мое имхо что && в финальной версии не будет, ибо это бяка. Ключевое слово, или новый символ.. вот что должно быть. Ещё раз напоминаю, что так решили с 2002 года и за 5 лет пока никому в голову не пришло, что это будет путать или ещё чем-то не устроит. |
Автор: LuckLess 14.06.07, 12:28 |
Цитата archimed7592 @ В двух словах: для того, чтобы отличать временные объекты от обычных, что может дать прирост производительности(при соответствующей поддержке со стороны реализации класса). Да я понял зачем они.. читал N раз (N > 2) имхо. Если есть ссылки на rvalue, то должны быть и указатели на rvalue. Почему? А почему бы и нет собственно? былоб полезно.. и если взятие адреса у T&& дает T*.. то вместо T& var = const_cast<T&> (rvalueRef); можно написать T& var = *&rvalueRef;//а это не круто, для типизированного языка как ЭС с плюсами. Ладно. Свое имхо сказал. Спорить не будем.. а то правда не флейм схожу уже.. |
Автор: archimed7592 14.06.07, 12:37 |
Цитата LuckLess @ имхо. Если есть ссылки на rvalue, то должны быть и указатели на rvalue. Почему? А почему бы и нет собственно? Ты сможешь придумать практическое применение эти "указателям на rvalue"? Мне вот в голову ничего не приходит... Понял чего ты хотел этим показать, но не уверен, что ты получишь то чего хотел... Цитата LuckLess @ можно написать T& var = *&rvalueRef;//а это не круто, для типизированного языка как ЭС с плюсами. Ты получишь точно такой же rvalue. Попробуй в студии написать ostream &s = *reinterpret_cast< ostream * >(NULL); - получишь еггог т.к. нельзя делать неконстантные ссылки на временные(читай rvalue) объекты. |
Автор: LuckLess 14.06.07, 12:44 |
Цитата archimed7592 @ Ты получишь точно такой же rvalue. Попробуй в студии написать ostream &s = *reinterpret_cast< ostream * >(NULL); - получишь еггог т.к. нельзя делать неконстантные ссылки на временные(читай rvalue) объекты. непроблема, яж псевдокодом написал. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> ... T&& rvalueRef; T* ptr = &rvalueRef;//ok T& lvalueRef = *ptr;//ravlue превратился в lvalue Придумал уже) <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> ... T&& rvalueRef; T* ptr = &rvalueRef;//Ошибка! ravlue превратился в lvalue! Низзя так! rvalue T* ptrRValue = &rvalueRef;//ok T& lvalueRef = *ptr;//ravlue не превратился в lvalue const T& constRef = *ptrRValue ;//ok T&& rvalueRef2 = *ptrRValue ;//ok T& lvalueRef = *ptrRValue;//ошибка низзя так. |
Автор: archimed7592 14.06.07, 13:04 |
LuckLess, не знаю насколько это можно считать разумным решением, но на данный момент стандарт трактует любую именнованную rvalue-ссылку как lvalue-ссылку. Т.е. на данный момент не нужно даже с указателями извращаться, чтобы "обмануть" компилятор. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> void f(T & a); void g(T && a) { f(a); // well-formed - несмотря на то, что "a" является как бы rvalue, мы без особых проблем передаём его по неконстантной lvalue-ссылке f(std::fwd(a)); // ill-formed - rvalue можно передавать только по константной lvalue-ссылке } T && a = ...; f(a); // well-formed Могу добавить, что возможно, мы просто ещё не привыкли. С практикой всё встанет на свои места и многие из принятых комитетом решений станут понятными и "очевидными"("как это мы раньше этого не понимали - это же очевидно" ). ИМХО, rvalue-ссылки примерно так же опасны, как и использование auto_ptr, но они того стоят. |
Автор: LuckLess 14.06.07, 13:08 |
не.. ну с такой постоновкой я к rvalue ссылкам вообще негативно отношусь. ПОнятно что иногда, для оптимизации.. можно допустить опасные синтаксические конструкции.. но когда эти синтаксические конструкции можно сделать безопасными, а их безопасными не делают.. этого я не понимаю вовсе.. Добавлено за что боролись.. на то и напоролись блин.. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> void f (double& d) { d = .555; } void ff (double&& d) { f (d); } int main () { int i = 0; ff (i); } Добавлено |
Автор: archimed7592 14.06.07, 13:11 |
LuckLess, у всего есть rationale... Эти rvalue-ссылки 5 лет "вылизывали". |
Автор: LuckLess 14.06.07, 13:12 |
Ну.. у них еще 2 года есть.. |
Автор: archimed7592 14.06.07, 13:19 |
С чего ты взял, что это скомпилируется? AFAIK, неявного каста из lvalue[-reference] of T в nonconst rvalue-reference of U нету. Ну там пока до конца не вылижут, как правило в WP не включают Добавлено И не два года, а меньше, чем полгода(см. первый пост, начало) |
Автор: LuckLess 14.06.07, 13:23 |
Цитата archimed7592 @ AFAIK, неявного каста из lvalue[-reference] of T в nonconst rvalue-reference of U нету. Гм... тут у нас int конвертируется в double и получается временная переменная типа double&& вродь все правильно да?? вот и все собстно.. Или мне пойти еще раз перечитать про rvalue reference.. ?? Добавлено так я и смотрел.. Цитата К октябрю 2007 года комитет запланировал публикацию законченного черновика стандарта C++09(который будет доступен публике для рассмотрения и критики). В октябре 2008 комитет внесёт окончательные коррективы в стандарт(и вот тут они одумаются!! ) и, наконец, на 2009 год(а тут уже все будет правильно... ) запланированна публикация нового стандарта "ISO/IEC 14883(2009): Programming Language C++". |
Автор: archimed7592 14.06.07, 13:27 |
Цитата LuckLess @ Гм... тут у нас int конвертируется в double и получается временная переменная типа double&& вродь все правильно да?? С чего ты взял, что у нас тут что-то конвертируется. Для того, чтобы чего-то конвертировалось, компилятор должен решить, что "надо бы сконвертировать". А решения он принимает на основе набора правил из стандарта и правила "надо бы конвертировать lvalue of T в rvalue-reference of U", AFAIK, нету. Добавлено Ну там же четко сказано, что в 2008 комитет только внесёт коррективы(ну мало ли каких там Core/Library Defect Issues найдут). Кардинально менять ничего не будут. Потом до 2009 будут слушать нотации ISO по формальности языка и исправлять некоторые места на более формальный язык(не меняя смысла сказанного). Ну и в 2009 выпустят С++09. |
Автор: LuckLess 14.06.07, 13:34 |
Цитата archimed7592 @ А решения он принимает на основе набора правил из стандарта и правила "надо бы конвертировать lvalue of T в rvalue-reference of U", AFAIK, нету. тогда rvalue ссылка совсем не похожа на lvalue ссылку и использовать && для нее я теперь вижу еще меньше смысла.. |
Автор: archimed7592 14.06.07, 13:37 |
а для lvalue-ссылки такое правило есть? <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> void f(double &); int i(0); f(i); // ill-formed |
Автор: LuckLess 14.06.07, 14:17 |
есть Цитата A variable declared to be a T&, that is “reference to type T (8.3.2), shall be initialized by an object, or function, of type T or by an object that can be converted into a T. не должно работать по другой причине Цитата A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows: — If the initializer expression — is an lvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with “cv2 T2,” or ... An expression which holds a temporary object resulting from a cast to a nonreference type is an rvalue(this а если ссылка const срабатывает Цитата Otherwise, the reference shall be to a non-volatile const type но для T&& это — is an lvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with “cv2 T2,” or должно заменится на — is an rvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with “cv2 T2,” or как мне кажется.. пойду какнить прокурю весь ман по новым ссылкам на rvalue когда время появится.. Добавлено не.. если нельзя написать void f (T2&&); ... T1 t; f (t);//где есть преобразование T1 в T2. то это нововведение выглядит вообще сомнительным. Это должно быть разрешено. |
Автор: archimed7592 14.06.07, 14:46 |
Вот все изменения: Цитата An expression which holds a temporary object resulting from a cast to a --- A variable declared to be a T& or T&&, that is ``reference to type T'' (dcl.ref), shall be initialized by an object, or function, of type T or by an object that can be converted into a T. ---- Otherwise, the reference shall be an lvalue-reference to a non-volatile const type (i.e., cv1 shall be const), or shall be an rvalue-reference. Только не понял при чём тут reference-compatibility... она вроде для отношений наследования... |
Автор: LuckLess 14.06.07, 14:53 |
Цитата archimed7592 @ Только не понял при чём тут reference-compatibility... она вроде для отношений наследования... Цитата is an lvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with “cv2 T2,” or битовые поля то уж точно не имеют отножение к наследованию Цитата archimed7592 @ Otherwise, the reference shall be an lvalue-reference to a non-volatile const type (i.e., cv1 shall be const), or shall be an rvalue-reference. Вот.. эта добавочка позволит компилироватся коду <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> void f (T2&&); ... T1 t; f (t);//где есть преобразование T1 в T2. ну.. мужики не глупые писали.. навернякак гдето есть добавочка которая не даст сделать <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> void f (double& d) { d = .555; } void ff (double&& d) { f (d); } int main () { int i = 0; ff (i); } и <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> T&& rvalueRef; T* ptr = &rvalueRef;//ok T& lvalueRef = *ptr;//ravlue превратился в lvalue хотя && будет резать мой глаз всю жизнь Добавлено вот подумал еще... я бы вообще не назвал бы это ссылкой.. пусть это будет именованный временный объект. без &&, а со значком какимнибудь.. или ключевым словом. Тогда терминология бы упростилась. Имхо имхо имхо... |
Автор: archimed7592 14.06.07, 15:48 |
Очень интересная штука, но, AFAIK, в С++09 её не будет |
Автор: archimed7592 15.06.07, 00:27 |
Чего НЕ будет в С++09 С большой долей уверенности можно заявить, что следующие пункты не будут включены в готовящийся стандарт С++09. С не меньшей долей уверенности можно считать, что все эти пункты будут в следующим за С++09 стандарте С++1x. Properties.(n1384, n1600, n1615) Имеющиеся во многих языках свойства. Предполагаемый синтаксис: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> class foo { int get_value (); int _bar; public: property<int> bar = { read = get_value, write = _bar }; }; Dynamic Libraries(n1400, n1418, n1428, n1496) Все мы в той или иной мере используем *.dll, *.so и т.п. динамические библиотеки. Их написание и использование сопровождаются нестандартными расширениями компиляторов. Комитет собирается стандартизировать динамические библиотеки. Предполагаемый синтаксис: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> shared int i; // shared linkage shared { int j; // shared linkage static int k; // internal linkage } shared class C { int c0; // no linkage static int c1; // shared linkage void f(); // shared linkage }; template <class T> class D { int d0; // no linkage static int d1; // no linkage void f(); // no linkage }; shared template <> D<int>; // D<int>::d1 and D<int>::f have shared linkage Class namespaces(n1420) При определении члена класса вне его(класса) определения приходится повсюду писать приставочку с именем класса. Предлагается упростить реализацию класса внего его определения. Предполагаемый синтаксис: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> class MyClass { typedef int value_type; value_type foo(); // declaration value_type bar(); // declaration }; MyClass::value_type MyClass::foo() // definition { } namespace class MyClass { value_type bar() // definition { } } // class definition class A { // declarations }; // elsewhere // class namespace definition namespace class A { // definitions } template <class T> class A { // declarations }; // elsewhere template <class T> namespace class A { // definitions } // full specialization template <> class A<void*> { // declarations }; // partial specialization template <class T> class A<T*> { // declarations }; // elsewhere // add definitions to a full specialization template<> namespace class A<void*> { // definitions } // add definitions to a partial specialization template <class T> namespace class A<T*> { // definitions } template <class T> class outer { template <class U> class inner { // declarations }; }; // elsewhere template <class T> namespace class outer { template <class U> namespace class inner { // definitions } } // equivalent template <class T> template <class U> namespace class outer<T>::inner { // definitions } class outer { class inner; // incomplete type }; namespace class outer { class inner { // declarations and definitions }; } namespace class outer::inner { // definitions } Security and Standard C Libraries(n1461) Включает в себя усовершенствования безопасности. Те самые, что многие видели в VS-8.0(7.0? 7.1?) - Security Enhancements in the CRT. Речь о printf_s, fscanf_s, blablabla_s. Т.к. стандартная библиотека С разрабатывалась в те времена, когда о безопасности думали в последнюю очередь, её архитектура в этом плане оставляет желать лучшего. Предлагается модифицировать все стандартные ф-ции по нескольким критериям. Multimethods(n1529) Мультиметод - это механизм, подобный виртуальным функциям, только выбор ф-ции, которая должна быть вызвана основывается на динамическом типе нескольких аргументов(в отличии от одного для вирутальных ф-ций - this). Предполагаемый синтаксис: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct shape {...}; struct square : shape {...}; struct triangle : shape {...}; bool overlap( virtual shape& a, virtual shape& b); bool overlap( static square& a, static triangle& b) {...} bool overlap( static triangle& a, static square& b) {...} bool overlap( static shape& a, static square& b) {...} bool overlap( static square& a, static shape& b) {...} Expliciting default parameters(n1466) Пока что для аргументов ф-ции по умолчанию есть чёткое требование: они должны быть в конце списка аргументов. В C++1x это требование скорее всего уберут и добавят возможностей работы с такими ф-циями. Предполагаемый синтаксис: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> void f(int x = 1, int y=2); void use() { f(default, 3); f( ); } template <class T> T* allocAndClone ( AllocatorType1 <T> alloc = MyAllocator <T>::instance(), T& prototype = T(), size_t size); template <class T> T* allocAndClone ( AllocatorType2 <T> alloc = MyAllocator <T>::instance(), T& prototype = T(), size_t size); void process(char t = ‘\n’); void process(const char* = “end of line”); void use(void) { MyClonableClass* p; p = allocAndClone( default<AllocatorType1<MyClonableClass> >, default, 10); process(default<char>); process(default); // error: ambiguity process(default<const char*>); process(default<float>); //error } Nested Namespace Definition(n1524) Предполагаемый синтаксис. Предлагается вместо этого: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> namespace grammars { namespace cplusplus { ... } } Писать вот это: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> namespace grammars::cplusplus { ... } Implicitly-Callable Functions(n1611) Неявно вызываемые ф-ции - это ф-ции, которые вызываются без применения постфиксного оператора "()". Предполагаемый синтаксис. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> double pi() implicit { return 3.1415926; } // ICF double two_pi() implicit { return 2.0 * pi; } // ICF; note also the implicit call double & pi() implicit { static double pi = 3.1; // poor approximation return pi; } // primary definition of ICF template function: template< class T = double > T pi() implicit { return 3.141592653589793; } // specializations, each an ICF based on primary declaration: template<> float pi<float >() { return 3.14159F; } template<> long double pi<long double>() { return 3.141592653589793L; } template< class T > T area( T radius ) { return pi<T> * radius * radius; } class Square { public: explicit Square( double s = 0.0 ) : side_(s) { } double & side() implicit { return side_; } // ... private: double side_; // length in cm }; class SerialNumberGenerator { public: SerialNumberGenerator( int start_from ) : next_(start_from) { } int operator()() implicit { return next_++; } private: int next_; }; SerialNumberGenerator unique( 1 ); // instantiation // ... cout << unique; // use Contract Programming(n1942) Идея добавить pre- и post-conditions, class invariant и block invariant. Эти вещи очень часто встречаются в документации обобщённых классов. Также встречаются в стандарте в описании стандартной библиотеки. Контрактное программирование имеет много плюсов. Хотя бы то, что код становится более самодокументированным. У компилятора появляется возможность делать некоторые предположения т.о. и возможность генерить более производительный код. Отладка и тестирование станут проще. И т.п. Предполагаемый синтаксис. Пример определения класса vector: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> /////////////////////////////////////// // Tools /////////////////////////////////////// template< class Iter, class T > bool all_equals( Iter first, Iter last, const T& val ) { /* for simplicity, let us assume T's can be compared */ } template< class Iter, class Size > bool equal_distance( Iter first, Iter last, Size size ) { /* internal tagging mechnism so even input iterators can be passed */ } /////////////////////////////////////// // New vector interface /////////////////////////////////////// template< class T, class Alloc = allocator<T> > class vector { invariant { ( size() == 0 ) == empty(); size() == std::distance( begin(), end() ); size() == std::distance( rbegin(), rend() ); size() <= capacity(); capacity() <= max_size(); } public: typedef Alloc allocator_type; typedef typename Alloc::pointer pointer; typedef typename Alloc::const_pointer const_pointer; typedef typename Alloc::reference reference; typedef typename Alloc::const_reference const_reference; typedef typename Alloc::value_type value_type; typedef ... iterator; typedef ... const_iterator; typedef ... size_type; typedef ... difference_type; typedef reverse_iterator<iterator> reverse_iterator; typedef reverse_iterator<const_iterator> const_reverse_iterator; vector() postcondition { empty(); } explicit vector( const Alloc& al ) postcondition { empty(); al == get_allocator(); } explicit vector( size_type count ) postcondition { size() == count; all_equals( begin(), end(), T() ); } vector( size_type count, const T& val ) postcondition { size() == count; all_equals( begin(), end(), val ); } vector( size_type count, const T& val, const Alloc& al ) postcondition { size == count; all_equals( begin(), end(), val ); al == get_allocator(); }: vector( const vector& right ) postcondition { right == *this; } template< class InIt > vector( InIt first, InIt last ) postcondition { equal_distance( first, last, size() ); } template< class InIt > vector( InIt first, InIt last, const Alloc& al ); postcondition { equal_distance( first, last, size() ); al == get_allocator(); } void reserve( size_type count ) precondition { count < max_size(); } postcondition { capacity() >= count; } size_type capacity() const; postcondition( result ) { result >= size(); } iterator begin() postcondition( result ) { if( empty() ) result == end(); } const_iterator begin() const postcondition( result ) { if( empty() ) result == end(); } iterator end(); const_iterator end() const; // .... }; Полную версию можно увидеть здесь. Улучшенные возможности оптимизации(n1664, n1703) Речь идёт о чём-то вроде спецификаций исключений, но, совсем в ином виде. Если спецификации исключений никак в оптимизации не помогают(дай Б-г, если они не ухудшают производительность), то предложенные спецификаторы, вроде, должны. Предложены спецификаторы: reading, writing, throwing, nothrow и pure. Их назначение - описать поведение ф-ции с точки зрения, интересной оптимизатору. Все они, в отличии от спецификаций исключений являются частью типа ф-ции. Предполагаемый синтаксис: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> int f( int ) reading() writing() throwing(); // --------------------------------------------------- // client code: #include <cerrno> int f( int x ) reading() writing(errno) throwing(); // library code: #include <cerrno> int f( int x ) reading() writing(errno) throwing() { errno = 0; return 7 * x; } // --------------------------------------------------- // Отличия от спецификаций исключений int f( int ) throw() { throw 2; // compiles; ultimately calls unexpected() } int g( int ) throwing() { throw 2; // fails to compile: inconsistent with g’s declaration } // --------------------------------------------------- float hypotenuse( float s1, float s2 ) writing() { return sqrt( s1*s1 + s2*s2 ); // error; sqrt writes to errno } // --------------------------------------------------- // pure <=> no reading, no writing no updating(доступ к volatile объектам) float hypotenuse( float s1, float s2 ) pure { return sqrt( s1*s1 + s2*s2 ); // error; sqrt is not pure } // --------------------------------------------------- float hypotenuse( float s1, float s2 ) pure nothrow { try { pure { return sqrt( s1*s1 + s2*s2 ); } } catch(...) { } } Callable Pointers to Members(n1695) Суть: указатели на члены можно будет вызывать. Относится как к методам, так и к членам-данным. Вызвав указатель на член нужно передать ему первым аргументом указатель(или ссылку) на объект. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct X { void f() const; }; int main() { std::vector<X> v; std::for_each( v.begin(), v.end(), &X::f ); // well-formed return 0; } Добавлено И как уже было сказано, не будет Opaque typedef: Новый стандарт C++: C++09 (сообщение #1601368) |
Автор: =MOHAX= 18.06.07, 06:40 |
А шаблоны по прежнему надо будет писать только в одном файле? Т.е. разделять из в *.h/*.cpp нельзя? |
Автор: archimed7592 18.06.07, 06:43 |
=MOHAX=, шаблоны и сейчас можно разделять в разные файлы - export template... Другой вопрос, что не все компиляторы это поддерживают. |
Автор: gryz 18.06.07, 07:21 |
Цитата archimed7592 @ =MOHAX=, шаблоны и сейчас можно разделять в разные файлы - export template... Другой вопрос, что не все компиляторы это поддерживают. А разве вообще есть такие компиляторы, которые полностью поддерживают export template?? |
Автор: archimed7592 18.06.07, 07:23 |
gryz, насчет полностью - не знаю, а так, AFAIK, comeau поддерживает... |
Автор: LuckLess 18.06.07, 11:38 |
интеловский вроде тоже поддерживает export.. |
Автор: archimed7592 18.06.07, 13:14 |
Вроде поддерживает: Экспорт шаблонов в icc Добавлено Хотя, может и поддерживает - сам не пробовал... Может чел чего-то неправильно делал просто... |
Автор: archimed7592 19.06.07, 00:48 |
Появилось обещанное описание TR1: TR1. Technical Report on C++ Library Extensions |
Автор: prografix 21.06.07, 09:03 |
А следующая конструкция будет легальной? <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> int n = 5; int a[n]; |
Автор: LuckLess 21.06.07, 09:32 |
Надеюсь нет. Она не нужна в С++. хотя может для совместимости с С99.. |
Автор: archimed7592 21.06.07, 09:37 |
prografix, нет. Согласен с LuckLess - она не нужна . |
Автор: Devilguard 28.06.07, 20:05 |
Цитата Expliciting default parameters(n1466) Пока что для аргументов ф-ции по умолчанию есть чёткое требование: они должны быть в конце списка аргументов. В C++1x это требование скорее всего уберут и добавят возможностей работы с такими ф-циями. Народ, это действительно кому-то нужно ??? Помоему это только усложнит читабельность кода. Когда видишь expr понять что это expr, а если сделать на манер паскаля, всегда сомнения будут. Да и не такие программисты лентяи чтобы 2 скобки не поставить. |
Автор: =MOHAX= 29.06.07, 04:37 |
Devilguard Ты не внимательно читаешь. |
Автор: archimed7592 01.07.07, 08:14 |
Devilguard, представь себе, да . Эта альтернатива именованным аргументам, описанным у Страуструпа в D&E. Суть проблемы в том, что порой, разработчикам библиотеки необходимо предоставить поведение по умолчанию, а мы хотим оставить это поведение таким же, за исключением одной маленькой детали, причём, мы хотим указать только эту деталь и всё. С именованными аргументами это можно сделать так же, как и в VB: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> window w0; // all default window w1(Color := 5, Height := 7); Только для именованных аргументов в С++ есть некоторые преграды, а вот для Expliciting default parameters - нету... Цитата Devilguard @ Помоему это только усложнит читабельность кода. Когда видишь expr понять что это expr, а если сделать на манер паскаля, всегда сомнения будут. Да и не такие программисты лентяи чтобы 2 скобки не поставить. Чует моё сердце, что ты говоришь про Implicitly-Callable Functions. Ничего не усложнит. Если ты пишешь expr, то где гарантия, что не будет вызвано неявное преобразование? |
Автор: bor.is 10.09.07, 19:25 |
imo не хватает только break n; ! (в смысле брейк через несколько циклов) даже в интерпретаторе php есть... это единственное место, где приходится использовать метки |
Автор: archimed7592 11.09.07, 05:28 |
А разве приходится? Неужели без них не обойтись? Я конечно слышал о том, что некто, разработчик драйвера TCP/IP стека для BSD сказал, мол, что если вам и удасться реализовать его без goto, то код будет ещё более запутанным и непонятным, но, всё равно, для меня воспользоваться goto - всё равно, что религию предать . |
Автор: Qraizer 13.09.07, 15:32 |
Тут где-то дальше по тексту была любопытная дискуссия. |
Автор: archimed7592 13.09.07, 16:09 |
IMHO, тут дискутировать нечего, ибо 1. Использование goto вырабатывает не очень хорошую(читай очень плохую) привычку "мыслить goto'ми", что сказывается на алгоритмах, в которых без goto можно обойтись без любых костылей. 2. Пока пишешь код для себя - на здоровье(но учесть п.1), но когда другой человек начнёт читать твой код с goto, то, хорошо, если его не стошнит. 3. Всегда есть лаконичный способ избежать goto. |
Автор: Hryak 13.09.07, 16:40 |
Ну, какая же это дискуссия. Вот у нас была дискуссия - исключения + стиль |
Автор: Qraizer 13.09.07, 18:48 |
archimed7592 Ты по ссылке-то ходил? Первый тезис вообще не аргумент, скорее ИМХО. Остальные два в ссылке опровергаются. Hryak Просто Boroda всех быстро уболтал, а вы так быстро не смогли |
Автор: archimed7592 13.09.07, 18:53 |
Ну, если сходить по ссылке Hryak'а, то можно увидеть, что это IMHO не только моё, но и Дейкстры . Как можно опровергнуть второй тезис я не очень то себе представляю(что, проводили следственный эксперимент: кого стошнит, а кого - нет ?), а опровержения третьему тезису я, увы, не нашёл . |
Автор: Qraizer 14.09.07, 09:46 |
Цитата archimed7592 @ Ко второму тезису я просто подошёл творчески и стал понимать его буквально. Насчёт опровержения - так Boroda-е так никто и предложил безгоутный вариант его примера. Сам сможешь написать и сравнить с гоутным решением? Я, кстати, могу эту задачу ещё усложнить. Как можно опровергнуть второй тезис я не очень то себе представляю(что, проводили следственный эксперимент: кого стошнит, а кого - нет ?), а опровержения третьему тезису я, увы, не нашёл . |
Автор: Hryak 14.09.07, 10:05 |
Цитата Qraizer @ Насчёт опровержения - так Boroda-е так никто и предложил безгоутный вариант его примера. Объявляешь счетчики цикла с инициализацией нулем, убираешь во всех for содержимое до первой ; и убираешь goto с меткой. Всё. |
Автор: gryz 14.09.07, 10:27 |
Цитата Qraizer @ Насчёт опровержения - так Boroda-е так никто и предложил безгоутный вариант его примера. Сам сможешь написать и сравнить с гоутным решением? Я, кстати, могу эту задачу ещё усложнить. Тут скорее возникает вопрос, каким образом вообще возник подобный код. Не существует ли более красивого алгоритма для решения задачи? В той теме это упоминается. |
Автор: archimed7592 14.09.07, 10:50 |
Вот о том и речь - использование goto даже очень редко, в последствии порождает подобный код(см. 1-й тезис, который "скорее ИМХО"). |
Автор: Qraizer 14.09.07, 18:23 |
Цитата Hryak @ Точно всё? Ничего не забыл? Попробуй. Хотя бы на двух вложенных циклах.Объявляешь счетчики цикла с инициализацией нулем, убираешь во всех for содержимое до первой ; и убираешь goto с меткой. Всё. Чтобы не флеймить, вот сразу более сложный пример, который я имел в виду: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> Нет смысла указывать так много вложенностей, поэтому я их уменьшил с двенадцати до трёх. В принципе, я могу предложить метапрограммное решение, разумеется безгоутное, которое к тому же параметризирует количество вложенных циклов, но оно конечно же будет на порядок сложнее, чем структурное безгоутное.#include <io.h> #include <conio.h> #include <fstream> #include <iostream> int main() { int i, j, k; if(_access("savedstate.dat", 4)==0) { std::ifstream inFile("savedstate.dat"); bool ok = true; ok = ok && inFile.read(reinterpret_cast<char*>(&i), sizeof(i)).gcount()==sizeof(i); ok = ok && inFile.read(reinterpret_cast<char*>(&j), sizeof(j)).gcount()==sizeof(j); ok = ok && inFile.read(reinterpret_cast<char*>(&k), sizeof(k)).gcount()==sizeof(k); if(ok && (inFile.good() || inFile.eof())) { std::cout << "The saved state is restored successful." << std::endl; goto resume; } return std::cerr << "The saved state restoring error. State file is wrong." << std::endl, 1; } for(i=0; i<10; ++i) for(j=i; j<10; ++j) for(k=j; k<10; ++k) { resume: /* ... */ if(kbhit() && getch() == '\x1B') { if(_access("savedstate.dat", 2)==0) remove("savedstate.dat"); std::ofstream outFile("savedstate.dat"); bool ok = true; ok = ok && outFile.write(reinterpret_cast<char*>(&i), sizeof(i)).good(); ok = ok && outFile.write(reinterpret_cast<char*>(&j), sizeof(j)).good(); ok = ok && outFile.write(reinterpret_cast<char*>(&k), sizeof(k)).good(); if(!(ok && (outFile.good() || outFile.eof()))) return std::cerr << "The state saving error." << std::endl, 1; return std::cout << "The state saved successful." << std::endl, 2; } } if(_access("savedstate.dat", 2)==0) remove("savedstate.dat"); ret } Цитата gryz @ Ну как же? Там же ясно сказано - это было написано для возможности очень долгий алгоритм прервать с сохранением состояния и с возможностью продолжить с запомненного состояния. Ну и что, что это было под DOSом, которая была однозадачной? Счас-то ведь тоже вполне может возникнуть потребность перегрузить ОСь зачем-нибудь...Тут скорее возникает вопрос, каким образом вообще возник подобный код. Не существует ли более красивого алгоритма для решения задачи? P.S. У этого форума есть возможность большие куски кода делать скроллируемыми, чтоб не занимали много места? |
Автор: Hryak 16.09.07, 11:11 |
Да, забыл. Цитата Чтобы не флеймить, вот сразу более сложный пример, который я имел в виду <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> #include <io.h> #include <conio.h> #include <fstream> #include <iostream> int main() { bool resuming = _access("savedstate.dat", 4)==0; for(int i=0; i<10; ++i) for(int j=i; j<10; ++j) for(int k=j; k<10; ++k) { if (resuming) { resuming = false; std::ifstream inFile("savedstate.dat"); bool ok = true; ok = ok && inFile.read(reinterpret_cast<char*>(&i), sizeof(i)).gcount()==sizeof(i); ok = ok && inFile.read(reinterpret_cast<char*>(&j), sizeof(j)).gcount()==sizeof(j); ok = ok && inFile.read(reinterpret_cast<char*>(&k), sizeof(k)).gcount()==sizeof(k); if(ok && (inFile.good() || inFile.eof())) std::cout << "The saved state is restored successful." << std::endl; return std::cerr << "The saved state restoring error. State file is wrong." << std::endl, 1; } /* ... */ if(kbhit() && getch() == '\x1B') { if(_access("savedstate.dat", 2)==0) remove("savedstate.dat"); std::ofstream outFile("savedstate.dat"); bool ok = true; ok = ok && outFile.write(reinterpret_cast<char*>(&i), sizeof(i)).good(); ok = ok && outFile.write(reinterpret_cast<char*>(&j), sizeof(j)).good(); ok = ok && outFile.write(reinterpret_cast<char*>(&k), sizeof(k)).good(); if(!(ok && (outFile.good() || outFile.eof()))) return std::cerr << "The state saving error." << std::endl, 1; return std::cout << "The state saved successful." << std::endl, 2; } } if(_access("savedstate.dat", 2)==0) remove("savedstate.dat"); ret } Вот только не надо со мной спорить, что твой вариант проще, лучше и т.п. Не теряй времени, спорить я с тобой не буду (свое отношение к goto я высказал в указанной мной ранее теме и отношение это с той поры не изменилось). Ты просил безгоутное решение - я его привел. Для людей, принципиально не использующих goto - очень даже сойдёт. Суть в чем - использование goto может сделать структурированную программу неструктурированной. Это goto в вину и вменяют. Однако, приведенная тобой задача изначально имеет антиструктурированный элемент прямо в своей постановке. Логично, что неструктурированность из постановки задачи перетекает в решение и вполне естественно применение тут goto. Но можно его и не применять... |
Автор: Qraizer 17.09.07, 10:42 |
Зачем же спорить? Количество потраченного времени на битие по клавишам и отладку в совокупности само рассудит. Текст вполне себе читабелен, хоть и чуточку менее интуитивен. Так что в целом авекватные результаты. Впрочем, переприсваивание параметров циклов в теле этих же циклов тоже как-то не совсем структурно, но это уже если придираться. Только не надо мне приписывать защиту goto. Спорить я начал с аргументами archimed7592-а, а отнюдь не с мнением достаточно авторитетных теоретиков. В лице Дейкстры, в частности. И ссылку привёл просто в подтверждение тезиса не упомянутого по имени "разработчика драйвера TCP/IP стека для BSD". |
Автор: archimed7592 17.09.07, 11:50 |
Ок, все остались при своём мнение, вопрос исчерпан . |
Автор: Hryak 17.09.07, 11:59 |
Цитата Qraizer @ Впрочем, переприсваивание параметров циклов в теле этих же циклов тоже как-то не совсем структурно, но это уже если придираться. Совершенно согласен. . |
Автор: amk 17.09.07, 17:50 |
Переприсваивание параметров вдобавок запутывает код почище тех же goto |
Автор: archimed7592 01.10.07, 08:11 |
Времени дописать обещанный(и уже как полтора месяца валяющийся почти законченным) обзор TR2 совсем нет. Также совсем нет времени просмотреть 4 пакета документов, вышедших с момента моего обзора, и написать что интересного там добавили. Но вот, наткнулся на краткий отчёт Саттера об одной из последних встреч. Помимо того о чём я уже писал выше там есть это: Language Support for Transporting Exceptions between Threads. Языковая поддержка обмена исключениями между потоками исполнения. (n2179) Очень радует, что поддержка многопоточности в С++09 будет не просто "пустым звуком" на бумаге, а вполне реальной возможностью языка без необходимости через строчку использовать грязные хаки и особенности платформы для реализации чего-либо более реального, чем абстрактный hello world в два потока. Суть нововведения в следующем: есть некий std::exception_ptr, который имеет семантику shared_ptr(т.е. разделяет владение - это в proposal явно не указано, но, насколько можно сделать вывод из описания copy_exception - это так). Вы можете: 1. Получить указатель на текущее исключение - current_exception( ) 2. Перебросить исключение на которое имеется такой указатель - rethrow_exception( exception_ptr p ) 3. Получить указатель на копию исключения - copy_exception( E e ). Зачем нужна последняя ф-ция я не особо догоняю(только если отдать другому потоку копию, а не оригинал, только зачем? ). В proposal написано, что она нужна из соображений эффективности 0_о. |
Автор: Славян 25.12.07, 14:40 |
Подскажите пожалуйста( может где я не так мыслю ? :-), собираются ли убрать или убрали уже предупреждение о том что строки вида : <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> int x; x|=-1; или <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> int x; x &= 0; выдают компилятором предупреждение ? // possible "ранняя операция перед присваиванием"... Так просто финальный код короче, а смысл очевидный - зануление и постановка всех бит в 1. |
Автор: Qraizer 25.12.07, 15:00 |
Ну, финальный код короче - ещё не факт, что быстрее. ИМХО, компилятору виднее, как это сделать эффективнее. Или ты думаешь, что он настолько тупой, что при случае сам до такой оптимизации не додумается? Додумывается, сам иногда видел, а где не видел, значит оптимизатор не посчитал нужным. Вывод: варнингу быть, ибо по-любому имеет место юзанье переменной до инициализации. Не надо привыкать к хакам, может аукнуться. |
Автор: Славян 26.12.07, 13:18 |
1.Да, я думаю, что он столь тупой. 2.Это не оптимизатор считает что-то нужным, а люди думают, сколько они сил готовы потратить, чтобы усилить оптимизатор. И часто махают рукой. 3.Использования переменной нету, ибо тут она вчистую превращается в ноль или полностью забивается единицами. Но, в целом, жаль, что Warning'у быть... :-( |
Автор: archimed7592 26.12.07, 13:21 |
А здесь тоже нету? <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> int x = ...; int y = x - x; |
Автор: Славян 26.12.07, 13:33 |
Да, и здесь компилятор (оптимизатор?) должен обнулить и всё. И чихать он должен хотеть на вычитание. Или я чего-то не понимаю? Ж:-) |
Автор: archimed7592 26.12.07, 13:55 |
Я попробую привести пример, который, возможно, прояснит ситуацию. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct A { A(int value) : value(value) { } protected: A operator -(const A &rhs) { return A(value - rhs.value); } private: int value; }; int main() { A x = 100; A y = x - x; // error } Здесь, несмотря на то, что происходит очевидное зануление, компилятор выдаст не просто предупреждение, а ошибку компиляции. Просто потому, что по Стандарту такой код корректной реализацией компилировать не должен(ill-formed code). Так вот, есть в Стандарте такое понятие как UB(undefined behavior). Это тоже ошибка, но корректная реализация имеет право скомпилировать код(и, как правило, скомпилирует). UB относится к тем случаям, которые далеко не всегда можно детектировать, так что реализация в праве вообще молчать как партизан на такую строку. Но, хорошая реализация в детектируемых случаях старается предупредить программиста, что он пользуется очень опасной конструкцией. Собственно говоря, об этом Вас компилятор и предупреждает. Он не говорит, что это работать будет как-то не так. Он говорит, что такой код по Стандарту имеет право вывести на экран "i'm is a result of code, written by foolish programmer". Если вы можете позволить себе пользоваться такими конструкциями, то можете успешно посмотреть на это предупреждение сквозь пальцы, а то и вообще выключить предупреждения в принципе(зачем они вам - вы же намного умнее компилятора с оптимизатором, правда, с такими амбициями, рекомендую посмотреть в сторону языка ассемблера). |
Автор: albom 26.12.07, 14:03 |
Ну для int может и не актуально, но вот если бы там был double, то x - x уже нельзя заменить на 0. |
Автор: Славян 26.12.07, 14:06 |
Спасибо. Да я давно туда смотрю и хожу, но С не бросишь полностью. Просто тут пример с классами, это принципиально громаднее выглядит, чем int y=x-x; И конечно хочется, чтобы на просто выглядящие вещи оптимизатор бы обращал побольше внимания, а не заваливал предупреждениями по делу и без оного. Ладно, буду сожалеть про себя далее... :-( :-) Добавлено И чем double хуже? Там ноль тоже нормальный, не надо ля! |
Автор: archimed7592 26.12.07, 14:11 |
Там результат вычисления неточный. А, если оперировать с нечислами, представленными double'ом, то вообще ни о каком нуле речи быть не может . |
Автор: Славян 26.12.07, 14:17 |
Я знаю. Просто за много лет у меня не было ни одной программы где я бы пользовался нечислами в double. А все неточности расчётов с числами тут оптимизатор должен забыть и написать обнуление. |
Автор: albom 26.12.07, 14:18 |
Если x - конечное число, то получим вполне точный ноль. Тут все ок. Но, если не инициализировать x, то там может оказатся значение +inf, -inf или даже NaN. Вот тут-то вычитание и вернет нам далеко не ноль. Добавлено Эх, опять я торможу с ответами |
Автор: archimed7592 26.12.07, 14:20 |
Цитата Славян @ Просто за много лет у меня не было ни одной программы где я бы пользовался нечислами в double Вы не поверите - они, порой, сами по себе появляются . Цитата Славян @ А все неточности расчётов с числами тут оптимизатор должен забыть и написать обнуление. Молодой человек, мы разговариваем о С++ или о каком-то, вымышленном Вами языке?(вопрос не риторический) |
Автор: amk 26.12.07, 18:30 |
Славян и другие Не вижу смысла пользоваться такими заумными конструкциями. Если ты знаешь, что там ноль, то так и пиши =0, нечего компилятору голову морочить, и тем кто потом программу читать будет (в основном им). |
Автор: Qraizer 27.12.07, 19:48 |
Славян Цитата Славян @ Вот когда ты будешь обладать не меньшим количеством информации, чем оптимизатор, тогда ты сможешь считать, что усиливаешь его. Заметь, он обладает куда бОльшей информацией о сгенерированном коде, чем ты, рассматривая ассеблерный листинг вблизи места предполагаемого вмешательства. А пока ты не доказал, хотя бы себе, что: считай, что ты оптимизатору будешь только мешать, ибо он тебя послушается даже в ущерб своей задаче. Даже выиграв локально тут, в целом можешь проиграть крупнее где-нибудь там, и не заметить этого. 2.Это не оптимизатор считает что-то нужным, а люди думают, сколько они сил готовы потратить, чтобы усилить оптимизатор. И часто махают рукой. |
Автор: Flex Ferrum 27.12.07, 20:54 |
Qraizer, все это замечательно. Только здесь же в холиварах ассемблерщики показывают, что оптимизатор (практически во всех перечисленных тобою пунктах) сливает проф. ассемблерщику. Т. е. я хочу сказать, что какие-то оптимизаторы, может быть, и умеют оптимизировать так, как ты описал, но таких - единицы. И те же компиляторы от Intel и Microsoft такими свойствами не обладают. Если считаешь иначе, прошу вот в эту: http://forum.sources.ru/index.php?showtopic=209970 тему. |
Автор: Qraizer 28.12.07, 14:17 |
Чесговоря, не нашёл я в этом топике того, что ты мне хотел показать. Читал не весь - большой уж больно - так что ткни меня носом конкретнее, плз. Либо я не понял, чтО ты хотел мне показать. Я подумал что "ассемблерные профессионалы, затыкающие оптимизаторы без особых усилий - это не редкость". Так что проясни, если не трудно. Далее. Оптимизаторы, которые я имел в виду, отнюдь не редкость. Только надо предоставить им достаточно информации для работы. Например, размеры строк кеша зависят от процессора, поэтому пока не укажешь оптимизатору каким-нибудь ключиком /G7 /QxP, на чём будет исполняться программа, максимум отдачи не получишь. Согласен, что несерьёзно настолько конкретизировать исполнительную платформу, но во-первых, ручной ассемблерный код тоже подвержен влиянию этой проблемы, во-вторых, есть ещё, к примеру, /QaxW, в-третьих, и вручную тоже можно разделить код под разные процессоры путём __declspec(cpu_specific) и __declspec(cpu_dispatch) и даже не использовать при этом ассемблер. Что касается потери оптимизации в общем при некотором выигрывании в частном, то /Qip сможет помочь, причём даже есть ассемблер, тут я слегка сутрировал, признаю. А для экстремалов есть /Qipo, только при его применении в зависимости от размера проекта в ожидании окончания его компиляции можно зачаржить часы в недельном отчёте от "отправился на обед" до "уехал на пикник". Для эстетов имеется /Qprof_gen и /Qprof_use, заодно и целевой модуль может получиться меньше в разы. Ну и наконец, всё это фуфло по сравнению с jit-time компиляцией. Правда, это уже не для плюсов. По крайней мере, пока. Недаром байт-кодинг в последнее время получает всё большее расспространение, ИМХО дойдёт и до плюсов. Зато решает проблемы с зависимостью от исполнительной платформы. Только, боюсь, здесь уже ассемблер будет просто в оффсайте. А если попытаться его заменить каким-нибудь специальным байт-кодным ассемблером, то это опять-таки внесёт уровень трансляции, который ассемблерные вставки призваны вроде как наоборот - убирать. P.S. Примеры управления оптимизацией взяты от Intel Compiler. Несколько слов в защиту обоих точек зрения: генерим ассемблерный вывод и внимательно рассматриваем комменты Intel Compilr-а, которыми он подробненько расписал, что по его мнению будет происходить при исполнении кода - всякие там штрафы от простоев, вероятности предсказаний переходов, распределение данных по строкам кеша и вероятности промахов, итп, и только после этого приступаем к попыткам помочь ему в каких-нибудь конкретных местах. Это я ещё смогу понять. В заключение. Я не отрицал возможности переплюнуть оптимизатор, так и сказал: "...пока ты не доказал, хотя бы себе,...". Если удалось доказать - то флаг в руки. Но лично мне это неинтересно. Каждый получает удовольствие от разных аспектов творческой составляющей нашей профессии. И я уже давно бросил соревноваться с компилятором в такой рутинной (для меня) области как бак-энд оптимизэйшн. Когда понадобилось написать _ecvtl() и _fcvtl для нативного x86-го long double, которые как известно MSVC для Win32 не поддерживает, тогда я этим занялся. Писал на асме и оптимизировал под P6. И - не буду скромничать - переплюнул их собственный _ecvt в три раза в производительности, а аналогичную C-реализацию компилятор соптимизировал хуже на 15%. И только добавив /arch:SSE2, я смог добиться от компилятора большей эффективности, что всё равно было неприемлимо, ибо функция как бы библиотечная. Потратил на это около двух дней - примерно впополаме на создание/отладку и оптимизацию/отладку. Теперь могу гордиться, мол, моя функция экономит вам столько-то там миллисекунд на выводе каждого long double. Вот пишу сейчас и думаю, нафиг я на это потратил столько времени? Разве что здесь похвастаться, а так практического эффекта никто не заметил и никогда не заметит. Да и было это один-единственный раз за последние лет восемь. В общем, мне это неинтересно, я лучше найду более другие причины потратить своё рабочее время. С пользой в сторону переносимости, гибкости, масштабируемости и надёжности. Если у кого другое ИМХО, да пожалуйста. Только для предотвращения воизбежания пусть почитает обо всём этом тут, ну а там пусть делает свои выводы и поступает сообразно им. Да и не всем "двигать мировую экономику и внедрять демократию", кому-то надо "...быть спортсменом или клоуном, чтоб политики и демократы могли иногда отдохнуть от подгаживания своим коллегам и расслабиться под зрелище смачной драки футбольных фанатов или там резню гладиаторов..." © Гай Юлий Орловский. |
Автор: Славян 28.12.07, 14:54 |
Блин, как всё сложно. Просто, поверите ли нет, ну дураку понятно, что код вида : <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> mov edi, edi push ebp mov ebp, esp mov eax, [eax+$xxyyzzww] pop ebp ret // вроде User32.dll или вида <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> fld1 fstp dword ptr [EBP+$xx] fldz fstp dw [EBP+$yy] fldz fstp dw [EBP+$zz] fldz fstp dw [EBP+$ww] fld1 fstp dword ptr [EBP+$hh] ... // glu32.dll не является оптимальным ну никак. И всякие оптимизации, приводящие к коду типа 1-примера( когда нефиг напрягаться компилятору за стэк), очевидно глупее моих : <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> mov eax, [eax+$...] ret Мне не нужно изучать кэши и промахи в него, ибо я суть оптимизатора вижу. И уж поверьте хоть и смотрю 'листинг вблизи места', вижу больше, чем он. Ну на кой ляд делать код <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> ?fld ... fld ... fxch ST(1), ST(0) ... И таких примеров у меня уже 76 категорий накопилось. Собираю, знаете ли ;-) Баг ниже вообще заполонил Microsoft'овские dll-ки. [BUG70] 648B05xxyy0000 mov EAX, FS:[$0000yyxx] :или 64A1xxyy0000 : mov EAX, FS:[$0000yyxx] : можно сэкономить на нулях! (используя префикс : смены способа адресации) так : 6764A1xxyy : mov EAX, FS:[$yyxx] : выигрыш = 2 байта(в 1 случае), или 1 байт (во втором)! : истинность = 100% (вроде бы) : идея баг'а из WinXP sp2 : user32.dll |
Автор: Qraizer 29.12.07, 18:33 |
Мда, маловаты у тебя фрагменты, как-то ты черезчур буквальНо поспринял слово "вблизи". Так что на безгрешность не претендую, однако... С первым примером для меня всё ясно. Первая инструкция - это двухбайтный ноп. Для чего он там - это вопрос уже не ко мне. Даже после самых дерьмовых оптимизаторов просто так нопы никогда не остаются, т.е. к оптимизации он не имеет прямого отношения. Игра со стековым фреймом - так без него плохо живётся всяким там отладчикам, профайлерам, кодековерам итп. А экспортируемые функции без стекового фрейма - это вообще нонсенс. Менеждер виртуальной памяти может это не одобрить по полной программе. Вообще же, ставишь галку компилеру, и он напрочь забывает о фреймах. И наоборот: не поставил галку - компилятор обязан создавать фреймы. Что, скажешь ни разу этой галкой не пользовался? Что-то я не пойму твоего недовольства этим фрагментом. Второй фрагмент вполне оптимален. Наверняка компилятору было сказано ключиком, чтобы он использовал строгое соответствие стандарту IEEE при работе с вещественной арифметикой. Вот он и не стал заменять FPU операции на CPUшные. А дальше я бы лучше уточнил, для какого процессора это оптимизация. Я вижу множество только-записей на шину, разделёнными паузами для предотвращения простоя блока предвыборки, который имеет меньший приоритет при конкуренции за грант шины по сравнению с записью данных. Паузы маленькие, всего в две микроинструкции + имеем простаивающий третий декодер, который компилятору просто нечем загрузить (впрочем, для P5 - этот код оптимизарован почти абсолютно), но если вдруг что, то одна из них даст возможность простаивающему блоку предвыборки успеть озадачить кеш, и в случае промаха теперь уже записи будут откладываться в буфере в ожидании гранта на шину. Вносимые fldz и fld1 паузы сами по себе не вредят производительности, т.к. эти команды на самом деле просто возвращают некое значение, которое тут же отправляется в память, т.е. в блоке неупорядоченного исполнения все они в совокупности не будут порождать никаких штрафов из-за зависимости по ST(0). Точнее, это всё-таки может случиться, но зависеть будет не от этого кода, а от окружающего контекста. Третий фрагмент - это вообще классика, начиная с P5. То, что тебе показалось глупостью, на самом деле позволяет выполняться последней загрузке параллельно со следующей после FXCH FPU-операцией, т.к. FXCH - это чуть ли не единственная инструкция, которая парабельна почти всем остальным FPU инструкциям (исключая трансцендентные, кажется). Выполняя её одновременно с предыдущей, мы ничего не теряем в тактах, зато "переименовываем" ST(0) в (в данном случае) ST(1), и следовательно какая-нибудь следующая FADD ST(0), ... будет работать параллельно с загрузкой в ST(1). Для P6 это имеет более слабый эффект, особенно на нативном для x86 long double, но всё-таки имеет. Четвёртый пример ты бы постеснялся приводить, если бы е лез в бутылку, а внимательнее внимал. Этот "баг" самое что ни на есть распространённое средство выравнивать длины инструкций под наиболее оптимальные. Так же как с нопами - иногда выгоднее использовать покороче, иногда - подлиннее. А вот твоя "оптимизация" предлагает поставить два префикса подряд, причём один из них AS. Ну-ну. Я думаю, не имеет смысла рассматривать все 76 категорий. Это число как-то подозрительно напоминает длину моего конспекта по оптимизации i486-P7, там было что-то около 70 пунктов. Да и archimed7592 прав - ты спросил, я ответил, а дальше давай куда-нибудь от этого топика, если будет желание. Только до окончания праздников, боюсь, у меня будут сложности с on-line-ом. И кстати, archimed7592 напомнил, инициализация присваиванием и твоя логической операцией нагружают разные исполнительные блоки процессора. Именно поэтому иногда оптимизаторы используют твою идею, иногда нет. Нагружает так, чтобы получилось поравномернее, а если в данном кокретном случае пофигу, то просто юзают "прямой" способ. |
Автор: trainer 31.12.07, 08:02 |
Вы когда спорите со Славяном, держите в уме вот это: Определить бинарный файл (сообщение #1816742) и вот это: Определить бинарный файл (сообщение #1817916) |
Автор: vedmak 12.01.08, 15:12 |
Я только начинаю учить шаблоны поэтому мне не очень понятно тут все В первом сообщении думал - Цитата что текущий стандарт, для заданного выражения E(a1,a2,...,aN), которое зависит от параметров a1,a2,...,aN, не позволяет написать такую ф-цию(или функтор), которая будет эквивалентна этому выражению. Думаю как это так? Ну например a1+a2+a3. Почему нельзя сделать функцию с параметрами a1,a2,a3, в которой будет строчка return a1+a2+a3? Потом идет первый пример - где "Всё бы хорошо, но нельзя сделать вызов f(1, 2, 3)." Попробовал сейчас в VS98: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // gh.cpp : Defines the entry point for the console application. // #include "stdafx.h" void g(int a1, int a2, int a3); template < class T1, class T2, class T3>void f(T1 &a1, T2 &a2, T3 &a3){ g(a1, a2, a3);} int main(int argc, char* argv[]) { f(1, 2, 3); return 0; } void g(int a1, int a2, int a3) { } Компилируется на ура! В общем вы слишком какие-то продвинутые вопросы обсуждаете... |
Автор: Qraizer 12.01.08, 16:01 |
Первое: VS98 компилировать не умеет. Второе: VC98 (или MSVC98, если угодно) является инструментом 10-летней давности, который не удовлетворяет требованиям текущего стандарта, и проверять им код на соответствие текущему стандарту, согласись, по меньшей мере неразумно. Возми чё поновее и повтори попытку. Третье: это ещё не всё, твой код некорректен, т.к. не каждая g(), имеющая ровно 3 параметра, сможет быть вызвана вот такой вот твоей f(). Собственно это как раз и утверждалось в цитированном тобой фрагменте. |
Автор: maxutov 15.02.08, 09:29 |
а какие компиляторы уже поддерживают стандарт? |
Автор: b-a1 15.02.08, 20:56 |
А какой сейчас год? На второй странице говорилось следующее: Цитата archimed7592 @ К слову уже сейчас можно скачать расширения g++ для поддержки variadic templates, concepts. расширение vs-8.0 для поддержки template aliases и т.д. |
Автор: maxutov 19.02.08, 12:44 |
Цитата b-a1 @ я имел ввиду беты много новых интересных вещей придумано в С++09 для приятного общения тестирование нужно проводить заранее |
Автор: b-a1 19.02.08, 16:43 |
maxutov, в этом плане, всё немного проще . Даже текущий стандарт(2003 года) полноценно поддерживается разве что comeau и то, не знаю в какой степени... Что же касается будущего стандарта - во первых, неизвестно, когда его окончательно утвердят(т.е. провозгласят 14882 устаревшим, а 14883 "актуальным"), не говоря уже о полном соответствии современных компиляторов. |
Автор: Flex Ferrum 31.03.08, 18:40 |
Не могу не поделиться новостью. Оригинал здесь: http://herbsutter.spaces.live.com/Blog/cns...B!785.entry На последнем заседании комитета по стандартизации среди всего прочего в стандарт C++0x включили поддержку lambda-функций. Полное описание можно прочитать в статье. Вкратце, новый стандарт будет допускать следующий код: Вывод коллекции на консоль: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // Writing a collection to cout, in today's C++, option 2: copy( w.begin(), w.end(), ostream_iterator<const Widget>( cout, " " ) ); // Writing a collection to cout, in C++0x: for_each( w.begin(), w.end(), []( const Widget& w ) { cout << w << " "; } ); Поиск элемента в массиве: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // Calling find_if using a functor, in today's C++: // outside the function, at namespace scope class GreaterThan { int weight; public: GreaterThan( int weight_ ) : weight(weight_) { } bool operator()( const Widget& w ) { return w.Weight() > weight; } }; // at point of use find_if( w.begin(), w.end(), GreaterThan(100) ); // Calling find_if using a lambda, in C++0x: find_if( w.begin(), w.end(), []( const Widget& w ) -> bool { w.Weight() > 100; } ); Алгоритмы как циклы: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> for_each( v.begin(), v.end(), []( Widget& w ) { ... ... use or modify w ... ... } ); transform( v.begin(), v.end(), output.begin(), []( const Widget& w ) -> AnotherType { ... return SomeResultCalculatedFrom( w ); } ); Выполнение кода в другом потоке: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> mypool.run( [] { cout << "Hello there (from the pool)"; } ); Также приняты в стандарт новый (альтернативный) формат объявления методов: direct-declarator: direct-declarator ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt exception-specificationopt -> type-id Т. е. позволяет задавать тип возвращаемого значения в конце объявления функции (что можно увидеть в приведенных выше фрагментах кода). Также позволили в объявлении функции использовать auto вместо типа возвращаемого значения. В этом случае тип функции был определен по типу возвращаемго значения в "самом последнем" операторе return. Чуть позже еще некоторые изменения опишу. |
Автор: Hryak 31.03.08, 18:54 |
Цитата Flex Ferrum @ На последнем заседании комитета по стандартизации среди всего прочего в стандарт C++0x включили поддержку lambda-функций. Хорошая новость! I λ... |
Автор: Flex Ferrum 31.03.08, 18:57 |
Надеюсь, не первоапрельская. |
Автор: archimed7592 31.03.08, 22:03 |
Yeehhhaaaaaa! Цитата Flex Ferrum @ Также приняты в стандарт новый (альтернативный) формат объявления методов: [...] Т. е. позволяет задавать тип возвращаемого значения в конце объявления функции (что можно увидеть в приведенных выше фрагментах кода). Если честно в выше приведённых фрагментах этого не заметил, но, правильно ли я понимаю, что теперь запись <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> можно будет заменить чем-то вродеSomeClassThatHaveVeryVeryLongName::SomeInternalType SomeClassThatHaveVeryVeryLongName::someMethod(...) { } <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> ??SomeClassThatHaveVeryVeryLongName::someMethod(...) -> SomeInternalType Цитата Flex Ferrum @ Также позволили в объявлении функции использовать auto вместо типа возвращаемого значения. В этом случае тип функции был определен по типу возвращаемго значения в "самом последнем" операторе return. Прям не нарадуешься на новый Стандарт . Добавлено |
Автор: Flex Ferrum 31.03.08, 22:10 |
Цитата archimed7592 @ можно будет заменить чем-то вроде SomeClassThatHaveVeryVeryLongName::someMethod(...) -> SomeInternalType ?? Видимо, да. Либо на <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> auto SomeClassThatHaveVeryVeryLongName::someMethod(...) {...} Добавлено Еще из интересных добавлений. Наследование конструкторов Т. е. можно будет писать: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> class Base { public: Base(T1, T2, T3, T4, T5, ...); }; class Derived : public Base { public: using Base::Base; // Автоматически объявляет конструктор Derived::Derived(T1, T2, T3, T4, T5, ...); }; inline-пространства имен. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> namespace Lib { inline namespace Lib_1 { template <typename T> class A; } template <typename T> void g(T); } ... struct MyClass { ... }; namespace Lib { template<> class A<MyClass> { ... }; } int main() { Lib::A<MyClass> a; g(a); // ok, Lib is an associated namespace of A } Подробности здесь: http://www.open-std.org/jtc1/sc22/wg21/doc.../2008/n2535.htm В библиотеку STL добавлены односвязные списки (думаю, в пояснениях не нуждается) (не менее вкусное!!!) C членов union-ов сняты все ограничения кроме одного - они не могут быть ссылочного типа!!!! Иными словами, теперь в union'ах можно объявлять члены любого типа, в том числе имеющего нетривиальные конструкторы и деструкторы. Вся ответственность, понятное дело, лежит на программисте. Но, как написано в соответствующем proposal, "union'ы - они такие от рождения". Правда, в этом случае все методы, которые для классов могут быть автосгенерированы самим компилятором по новому стандарту обозначаются как deleted-члены. Таким образом, на программиста ложится работа по явному объявлению и определению конструкторов/деструкторов/операторов присваивания для такого рода объединений. Теперь создание вариантных типов становится задачей практически тривиальной... Ключевое слово auto окончательно разжаловано и из storage-class спецификаторов Думаю, в комментариях тоже не нуждается. auto переквалифицировалось в автоопределение типа... Вложенные исключения В STL введен новый тип исключения - std::nested_exception, позволяющий оборачивать исключения одно в другое. |
Автор: Cechmanek 28.04.08, 08:32 |
Flex Ferrum Цитата На последнем заседании комитета по стандартизации среди всего прочего в стандарт C++0x включили поддержку lambda-функций. Полное описание можно прочитать в статье. Вкратце, новый стандарт будет допускать следующий код: Вывод коллекции на консоль: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // Writing a collection to cout, in today's C++, option 2: copy( w.begin(), w.end(), ostream_iterator<const Widget>( cout, " " ) ); // Writing a collection to cout, in C++0x: for_each( w.begin(), w.end(), []( const Widget& w ) { cout << w << " "; } ); Что за скобки [] перед (const Widget) ? Что они означают ? |
Автор: Hryak 28.04.08, 09:03 |
Означают то, что за ними располагается определение ламбда-функции. |
Автор: Cechmanek 28.04.08, 09:36 |
хм ... очень интересное решение. |
Автор: Flex Ferrum 06.05.08, 06:02 |
Для желающих попробовать некоторые фишки стандарта уже сейчас, gcc 4.3 под винду можно залить отсюда: http://www.tdragon.net/recentgcc/ |
Автор: Flex Ferrum 06.05.08, 07:46 |
Проверено. Работает. |
Автор: Flex Ferrum 07.05.08, 11:31 |
Текущее состояние предложений по изменениям в стандарте можно увидеть на этой странице: State of C++ Evolution |
Автор: Alek86 10.05.08, 09:06 |
не хочется долго рыскать по незнакомым докам, потому тут спрошу собираются в новом стандарте изменить STL в более удобную сторону (как в бусте) - к примеру добавить возможность передавать в алгоритмы весь контейнер (чтобы не писать кажжый раз xx.begin(), xx.end() и иметь возможность вложенных вызовов)? |
Автор: archimed7592 10.05.08, 12:51 |
Alek86 Library Evolution Цитата ... New Language Support Planned for C++0x These propsals take advantage of some new language feature, either voted into the Core Language or anticipated for the Final Candidate Document. ... N2245 Range Utilities for C++0x Thorsten Ottosen ... New Library Components Planned for a Future TR These papers present libraries that are actively under consideration for a future TR. The Library Working Group is committed to an ongoing process of TRs, adopting libraries 'when they are ready'. As such, there is no target TR number associated with any given proposal. ... N1871 Range Library Proposal Thorsten Ottosen N2068 Range Library Core Thorsten Ottosen ... В общем я так и не понял, то ли range в TR включат, то ли в 14883... |
Автор: archimed7592 30.09.08, 19:02 |
Ты считаешь, есть язык, не имеющий существенных огрехов? Я давно такой ищу... |
Автор: FireZilla 30.09.08, 19:28 |
Нет я не считаю что языков без "огрехов" нет. Я считаю что комитет по стандартизации С++ занимается изобретением новых "закорлючек" вместо того чтобы исправить старые недостатики. Причем как раз эти "закрлючки" как раз и предназначены для обхода недостатков. IMHO Типы вроде int8_fast и т.д. не испрявят ситуацию когда я всеравно могу написать long и на разных процессорах это будет либо 16 либо 32 либо 64 бита. Или нам всем дружно взятся и перерефакторить миллионы строк кода. И вообще почитай примеры кода которые ты сам выложил в первом посте, если говорить совершенно откровенно если вдуматся то обявления вроде 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(); } Не так уж и далеко от Brainfuck кода. |
Автор: Flex Ferrum 30.09.08, 19:33 |
Цитата FireZilla @ Из-за остутвия finally приходится использовать смарты, которые добавляют к программе лишних 100-200 КБ кода, даже если в принципе нет особой нужды в подсчете ссылок и т.п. Нет, это . Трижды. Активно программируя на шарпе (где используется этот самый try-finally) и на С++ (где его нет), лучше все же в С++. Типичная конструкция в шарпе: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> OleDbDataReader r = null; try { OleDbCommand cmd = new OleDbCommand(check_sql, m_Connection); AddParameterInt(cmd, (int)ai.ID); r = cmd.ExecuteReader(); if (r.Read()) UpdateIniniator(ai); else InsertInitiator(ai); } finally { if (r != null) r.Close(); } И так везде, где требуется контроль освобождения ресурсов при выходе из блока/функции. Или (о! небеса!) - использование для тех же целей using: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> using (OleDbDataReader r1 = null) { // ... using (OleDbDataReader r2 = null) { // ... } } Хорошо, если переменных - одна-две. А если их три-пять? Так что, за finally агитировать не надо. Цитата FireZilla @ А теперь про то что не попало в стандарт и слава богу - свойства. Имея дело с делфи я пришел к выводу что подобная практика фактически бесполезна. Свойства легко реализуются через сетеры и гетеры (т.е функции) которые к томуже могут быть автоматичики сгенерированны ИДЕ. Спорный тезис. Добавлено Цитата FireZilla @ IMHO Типы вроде int8_fast и т.д. не испрявят ситуацию когда я всеравно могу написать long и на разных процессорах это будет либо 16 либо 32 либо 64 бита. Или нам всем дружно взятся и перерефакторить миллионы строк кода. И что? Ситуаций, когда нужны типы фиксированной длины - не так много. Точнее, они ограничиваются только наличием требований бинарной совместимости (серелизация/десерелизация данных). Все! В остальных случаях совершенно побарабану - сколько именно места занимает int или long. |
Автор: archimed7592 30.09.08, 19:41 |
Смотря что понимать под исправлениями. Breaking changes - это не совсем исправления. При появлении таковых бунт устроит намного большее число пользователей языка С++, чем тех, кто агиттировал за эти изменения. Рефакторить не хочешь, но хочешь "исправления" старого кода(а что его исправлять? Если он старый, то он либо работает, либо он никому не нужен не работающий). Цитата FireZilla @ И вообще почитай примеры кода которые ты сам выложил в первом посте, если говорить совершенно откровенно если вдуматся то обявления вроде Я вот смотрю на приводимые тобою примеры и совсем не понимаю, что ты ими показать пытаешься... |
Автор: Dantes 30.09.08, 20:32 |
Цитата archimed7592 @ Я вот смотрю на приводимые тобою примеры и совсем не понимаю, что ты ими показать пытаешься... Учитывая, что в трех из них написан бред, а также судя по остальному тексту, можно предположить, что их автор - троль |
Автор: Hsilgos 30.09.08, 21:01 |
Я чё та прифигел... Неужели аффтар прав и здесь будет именно такой ответ? Нет компилера под рукой, подскажите, а ? <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> class A { public: virtual void func() { std::cout<<"This is A class"<<std::endl; } }; class B: public A { public: virtual void func() { std::cout<<"This is B class"<<std::endl; } }; ... A a; a.funck(); B b; b.funck(); This is A class This is A class |
Автор: Flex Ferrum 30.09.08, 21:07 |
Нет, аффтар не прав. Он явно не проверял код перед отправкой поста. Как, впрочем, и в следующем примере. Код <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> bool validResult = false; int i = -1; while(!validResult) { i ++; switch(i) { case 0: break; case 1: break; case 2: break; case 3: validResult = 1; break; } std::cout << "i = " << i << ", validResult = " << validResult << std::endl; } std::cout << "Loop finished" << std::endl; честно отрабатывает положенные 4 итерации. По этому с какого перепугу автор поста решил, что break внутри switch прерывает внешний цикл - известно только автору... |
Автор: Hsilgos 30.09.08, 21:26 |
Ну с шаблонами - ладно, шаблоны это, можно сказать, отдельный подъязык в языке С++. (По моему скромному имхо, язык программирования должен стремиться к такому виду.) Цитата На последнем заседании комитета по стандартизации среди всего прочего в стандарт C++0x включили поддержку lambda-функций. Лямбда функции тоже ничё, давно пора. Хотя для восприятия это будет сложновато. И, думаю, будет рассадник копипаста у нерадивых программистов. И да... какая теперь разница будет между <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> for_each( v.begin(), v.end(), []( Widget& w ) { ... ... use or modify w ... ... } ); и <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> for(iterator it = v.begin(),itEnd = v.end(); it != itEnd; ++it) { use or modify "*it"; } ??? Цитата В библиотеку STL добавлены односвязные списки Нафига? Меньше памяти? Цитата Также позволили в объявлении функции использовать auto вместо типа возвращаемого значения. В этом случае тип функции был определен по типу возвращаемго значения в "самом последнем" операторе return. Ключевое слово auto будет только для шаблонов или в любом месте использоваться? Для чего это вообще то нужно? Теперь при виде метода придется лезть внутр и смотреть, какой же тип возвращает функция... Да и тот будет выбираться из какого-то непонятного правила "последнего return". По-моему, это плохо. Убедите меня в обратном =)) Нда, я как посмотрю, язык С++ становится всё сложнее и сложнее. Владеть полностью С++ в будущем будет означать принадлежность к касте этаких тру-бородатых, заросших программистов в очках У меня неоднозначное отношение к этому. Не приведет ли это к смерти языка, как очень сложного? Добавлено Цитата Из-за остутвия finally приходится использовать смарты, которые добавляют к программе лишних 100-200 КБ кода, даже если в принципе нет особой нужды в подсчете ссылок и т.п. А я вот всё пытаюсь автоматизировать такие вещи. Всегда может оказаться место, где досмотришь. не удалишь, не освободишь, а потом ищешь трудноуловимые ошибки Тем более смарты иногда очень существенно уменьшают код (где-то слышал термин, опимывающий "полезность" кода на количество строчек...). Ненадо заботится, что при вызоде из функции в 4-х местах забудешь освободить ресурсы. Цитата char a[1]; a[10] = 100; Сам себе противоречишь. Хочешь, чтобы С++ небыл похож на С и в то же время используешь С-шные rконструкции. vector + vector::at тебе в руки. |
Автор: archimed7592 30.09.08, 21:40 |
Первый вариант более гибкий. Ключевое слово auto имеет весьма посредственное отношение к шаблонам... Для гибкости. Знаешь как в C# удобно пользоваться var?(IIRC, начиная с 3.0 появилось) Цитата Hsilgos @ Теперь при виде метода придется лезть внутр и смотреть, какой же тип возвращает функция... Это самое вкусное - концептуальное программирование. Ты не знаешь какого типа возвращённый тебе объект, но ты знаешь концепт, реализуемый этим объектом. Концепт - это такой контракт между библиотекой и её пользователем. К примеру, можно встретить в стандарте в описании STL(iterator requirements, sequence container requirements and so on), в бусте(threads, mutex, etc.). А с появлением валидируемых концептов в самом языке это перестаёт быть пустыми словами. Ещё большую гибкость предоставляют концепт-мапы, позволяющие создавать адаптеры от одного концепта к другому. |
Автор: Flex Ferrum 30.09.08, 21:40 |
Кхм-кхм... Читаем на этой странице: GCC 4.3.2 changes: Цитата An experimental parallel mode has been added. This is a parallel implementation of many C++ Standard library algorithms, like std::accumulate, std::for_each, std::transform, or std::sort, to give but four examples. These algorithms can be substituted for the normal (sequential) libstdc++ algorithms on a piecemeal basis, or all existing algorithms can be transformed via the -D_GLIBCXX_PARALLEL macro. Теперь ответ на твой вопрос очевиден. С одной стороны, да. С другой - открывает новые возможности. Вот тебе задачка. Тебе нужно протестировать как один класс работает с объектами другого класса - в правильном ли порядке методы вызываются и все такое. Если взаимодействие построено на базе интерфейсов, то тебе ничего не стоит написать такую реализацию класса, с которым производится взаимодействие, что она будет вызывать делегаты. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct ISomeInterface { public virtual void Foo1() = 0; public virtual void Foo2() = 0; public virtual void Foo3() = 0; }; //... class TestClassThunk : public ISomeInterface { public: std::function<void ()> FuncDelegate; FuncDelegate OnFoo1; FuncDelegate OnFoo2; FuncDelegate OnFoo3; void Foo1() {OnFoo1();} void Foo2() {OnFoo2();} void Foo3() {OnFoo3();} }; //... void TestSomething() { TesteeClass target; TestClassThunk tester; bool foo1_called = false; tester.OnFoo1 = []() {foo1_called = true;} target.SomeMethod(tester); assert(foo1_called); } Существующими методами ты такое напишешь с бОльшим трудом. Без boost::lambda/boost::phoenix - так вообще никак. Чтобы вместо: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> std::map<std::string, std::vector<int> >::const_iterator p = m_Map.begin(); писать <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> auto p = m_Map.cbegin(); |
Автор: Hsilgos 30.09.08, 21:42 |
Цитата 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(); } А чё, это нормально... вот это больше на brainfuck похоже <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> typedef return_type(T::*MemFun)(const arg_type& v1); return_type ret = (obj->*MemFun)(val); |
Автор: Flex Ferrum 30.09.08, 21:44 |
Это еще не brainfuck... |
Автор: archimed7592 30.09.08, 21:45 |
Мухаха, сколько же после этого сломается кода, который делал расчёт на порядок вызова функтора . |
Автор: Flex Ferrum 30.09.08, 21:52 |
Цитата archimed7592 @ Мухаха, сколько же после этого сломается кода, который делал расчёт на порядок вызова функтора . Ну, тут уж народ сами себе злобные буратинки... |
Автор: Hsilgos 30.09.08, 21:52 |
Цитата Flex Ferrum @ Чтобы вместо: std::map<std::string, std::vector<int> >::const_iterator p = m_Map.begin(); писать auto p = m_Map.cbegin(); Хм. Значит ли это, что теперь абсолютно люой тип можно булет описать как auto? Для таких задач хорошо использовался typedef Цитата Это еще не brainfuck Ну для нас с тобой - нет. А вот я как-то видел выражения лица у человека, который пишет на C# при виде этого кода. Он мне говорит, "Для меня это примерно каквот такой код #*&#HKkjh##@#" =) |
Автор: Flex Ferrum 30.09.08, 21:53 |
Хотя, нередко std::accumulate используется именно для последовательной сцепки элементов. В паралельном режиме результат, гм... непредсказуем... Добавлено Видимо. Ну, не всегда его использование полностью оправдано. Т. е. использовать typedef только для того, чтобы упростит текст программы (а не для введение нового псевдонима типа) - не есть гуд. |
Автор: archimed7592 30.09.08, 22:04 |
Что значит описать? auto - это вариант определиния переменной, аналогичный использованию deduced template parameter в аргументах ф-ции: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> Означает ли это, что абсолютно любой тип можно описать как T? template< class T > void foo(const T &arg) { // ... } typedef менее гибкий. См. какую возможно даёт auto: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // представим, что у нас есть концепт string который обязывает // к наличию метода length() с соответствующей семантикой(и др. методов, ессно) // library code SomeLibrary::SomeStringImplementation getSomeValue(); // client code auto value = getSomeValue(); // год спустя вышла другая библиотека, предоставляющая намного более эффективную реализацию концепта string // library code YetAnotherLibrary::EffectiveStringImplementation getSomeValue(); // client code auto value = getSomeValue(); // не меняется Это предоставляет просто шикарные перспективы для проектирования чёрных ящиков за которыми, я считаю, будущее программирования. Концепты, в свою очередь - это очень эффективный(хотя бы по той причине, что они compile time) аналог интерфейсов. typedef, в свою очередь, придётся менять на стороне клиента. При выходе новой версии библиотеки, с новыми концептами, старые можно будет обернуть в концепт-мапы тем самым сохранив backward compatibility. |
Автор: Hsilgos 30.09.08, 22:06 |
Не стал копировать весь пример... Цитата bool foo1_called = false; tester.OnFoo1 = []() {foo1_called = true;} Это пример попахивает возвращением к глобальным переменным. Но в принципе суть я уловил, своё применение фишка найдет, иногда такое ой как надо |
Автор: archimed7592 30.09.08, 22:08 |
Это зависит от программиста и от того, как он воспользуется предоставляемыми инструментами. |
Автор: Flex Ferrum 30.09.08, 22:13 |
Ну не скажи. Лямбды они тем и хороши, что могут работать в контексте инициализации функтора. |
Автор: archimed7592 30.09.08, 22:15 |
Цитата Flex Ferrum @ Хотя, нередко std::accumulate используется именно для последовательной сцепки элементов. В паралельном режиме результат, гм... непредсказуем... Вот это, к слову говоря, открывает одну палку С++ о двух концах. С одной стороны, стремление в С++ к минимализму, в принципе, мне понятно и чем-то изнутри меня это стремление одобряется. С другой стороны, крайность, с которой С++ проповедует минимализм меня немного ужасает. Вот взять std::string и QString - в первом всего по минимум, другим, OTOH, очень удобно пользоваться. Почему не сделают какой-никакой аналог интерфейса QString, .NET::System::String, etc.? Аналогично с алгоритмами - почему нет строковых алгоритмов, в частности concatenate/join мне не совсем понятно... Его стоило бы ввести даже если бы для accumulate был бы специфицирован порядок аккумуляции по той простой причине, что я хочу сказать в коде "я объединяю коллекцию строк", а не "я аккумулирую коллекцию строк". |
Автор: Hsilgos 30.09.08, 22:18 |
archimed7592 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // library code SomeLibrary1::SomeClassImplementation1 getSomeValue1(); // library code SomeLibrary2::SomeClassImplementation2 getSomeValue2(); // client code auto value1 = getSomeValue1(); auto value2 = getSomeValue2(); // ок. А теперь я хочу вызвать какие-то методы value1.SomeMethod1(); value2.SomeMethod2(); // Э... А как их различать? А как компилятор различает эти 2 разных типа? // А может, так? (SomeLibrary1::SomeClassImplementation1)value1.SomeMethod1(); (SomeLibrary1::SomeClassImplementation1)value2.SomeMethod2(); // Фуууууу.... |
Автор: Flex Ferrum 30.09.08, 22:21 |
Цитата archimed7592 @ Его стоило бы ввести даже если бы для accumulate был бы специфицирован порядок аккумуляции по той простой причине, что я хочу сказать в коде "я объединяю коллекцию строк", а не "я аккумулирую коллекцию строк". Ээээ... <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> std::vector<string> strings = ....; std::string result = boost::join(strings, "\\"); string_algo |
Автор: Hsilgos 30.09.08, 22:35 |
И вообще, я такой код уже где-то видел. Э... Дай мне мой маразм памяти... <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 10 DEM i1 = 12; 20 DEM i2 = 'Hello' 30 Print i2; 40 Print i1; 50 goto 10 Как-то так |
Автор: Flex Ferrum 30.09.08, 22:38 |
Правда, тут нужно учесть разницу между compile-time и run-time типизацией. |
Автор: archimed7592 01.10.08, 00:19 |
Ээээ, это буст, я про стандартную библиотеку. Почему нет в стандарте - одному комитету известно... Hsilgos, либо я тебя не понимаю, либо ты меня. Третьего не дано . Вот зачем ему что-то различать? Он и так знает какого типа переменная... Опять же, провожу аналогию с шаблонными ф-циями: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // library code template< class StringT > void foo(const StringT &str) { int len = str.length(); // как он различает? А может так: ... Фyyyyуу std::cout << "passed string length equals to " << len << std::endl; // ... } // client code std::string ss = "standard string"; QString qs = "qt string"; foo(ss); foo(qs); Ты давно пользуешься тем свойством компилятора, что он всегда знает статические типы переменных(по крайней мере язык так устроен, что он не может не знать) просто, видимо, не до конца осознаёшь этого... |
Автор: Flex Ferrum 01.10.08, 07:56 |
Цитата archimed7592 @ Ээээ, это буст, я про стандартную библиотеку. Почему нет в стандарте - одному комитету известно... Тебе шашечки или ехать? |
Автор: archimed7592 01.10.08, 08:02 |
Мне бы скрестить наилучшии стороны C++, Java и C#, включая их фреймворки . |
Автор: Flex Ferrum 01.10.08, 08:07 |
О как... ИМХО, это из области фантастики... |
Автор: archimed7592 01.10.08, 08:07 |
Это ещё почему? |
Автор: Flex Ferrum 01.10.08, 08:10 |
Концепции слишком сильно различаются. Я думаю, например, что если бы было возможно перенести плюсовые шаблоны в шарп - это было бы сделано, но вместо этого там какие-то generic'и... И это, вообщем то, объяснимо. Тот же reflection накладывает свои ограничения. Ну и т. д. |
Автор: archimed7592 01.10.08, 08:14 |
Цитата Flex Ferrum @ Концепции слишком сильно различаются. Я думаю, например, что если бы было возможно перенести плюсовые шаблоны в шарп - это было бы сделано, но вместо этого там какие-то generic'и... И это, вообщем то, объяснимо. Тот же reflection накладывает свои ограничения. Ну и т. д. Флекс, я вот, хоть убей, никак не пойму, что мешает шаблонам жить рядом с дженериками, рефлексивным классам рядом с нерефлексивными, управляемой куче и неуправляемой, множественному наследованию и интерфейсам и т.д... Добавлено BTW, я это отлично понимаю, но у меня в голове уже некоторое время крутится идея как эти концепции скрестить для получения более эффективной. |
Автор: Flex Ferrum 01.10.08, 08:29 |
Цитата archimed7592 @ Флекс, я вот, хоть убей, никак не пойму, что мешает шаблонам жить рядом с дженериками, рефлексивным классам рядом с нерефлексивными, управляемой куче и неуправляемой, множественному наследованию и интерфейсам и т.д... Судя по всему, технически это совместить очень сложно. |
Автор: archimed7592 01.10.08, 08:34 |
Флекс, ну у тебя же на компьютере нормально сосуществует куча нативного кода и ява/дотнеты-машины? Кстати, managed C++ - совмещено? Совмещено... Просто плохо и неудобно совмещено(по понятным причинам - целью было добится какой-нибудь совместимости, а ценою чего эта совместимость достанется никого, видимо, не волновало). |
Автор: FireZilla 01.10.08, 10:45 |
Цитата Flex Ferrum @ Цитата FireZilla @ Из-за остутвия finally приходится использовать смарты, которые добавляют к программе лишних 100-200 КБ кода, даже если в принципе нет особой нужды в подсчете ссылок и т.п. Нет, это . Трижды. Активно программируя на шарпе (где используется этот самый try-finally) и на С++ (где его нет), лучше все же в С++. Типичная конструкция в шарпе: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> OleDbDataReader r = null; try { OleDbCommand cmd = new OleDbCommand(check_sql, m_Connection); AddParameterInt(cmd, (int)ai.ID); r = cmd.ExecuteReader(); if (r.Read()) UpdateIniniator(ai); else InsertInitiator(ai); } finally { if (r != null) r.Close(); } И так везде, где требуется контроль освобождения ресурсов при выходе из блока/функции. Или (о! небеса!) - использование для тех же целей using: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> using (OleDbDataReader r1 = null) { // ... using (OleDbDataReader r2 = null) { // ... } } Хорошо, если переменных - одна-две. А если их три-пять? Так что, за finally агитировать не надо. Цитата FireZilla @ А теперь про то что не попало в стандарт и слава богу - свойства. Имея дело с делфи я пришел к выводу что подобная практика фактически бесполезна. Свойства легко реализуются через сетеры и гетеры (т.е функции) которые к томуже могут быть автоматичики сгенерированны ИДЕ. Спорный тезис. Добавлено Цитата FireZilla @ IMHO Типы вроде int8_fast и т.д. не испрявят ситуацию когда я всеравно могу написать long и на разных процессорах это будет либо 16 либо 32 либо 64 бита. Или нам всем дружно взятся и перерефакторить миллионы строк кода. И что? Ситуаций, когда нужны типы фиксированной длины - не так много. Точнее, они ограничиваются только наличием требований бинарной совместимости (серелизация/десерелизация данных). Все! В остальных случаях совершенно побарабану - сколько именно места занимает int или long. Мда, все это хорошо если ты программируеш единственный инструмент - Микропроцессор архитектуры Intel. Нашему же вниманию предлагается международный стандарт на язык программирования для любого типа процессоров и контроллеров. И вообще у меня сложилось впечатление что комитет стандартизирует не язык программирования, а собсвенно компилятор фирмы Intel. Язык как то начинает быть похожим на ассемблер intel. По всей видимости борьба с коррупцией набриает обороты, броремся так что даже американцы стали берать взятки А касательно finally я скажу просто, если у меня всего одна переменная, зачем тогда мне прибавлять к программе хеадер с 5 000 строк кода А про то что по барабану какой длинны тип данных, это ты загнул. Можно подумать инеграция кода написанного на разных языках, сетьвая передача данных, обмен данными с БД и вообще допустим проверка установки 3-го бита в 1 некоторой переменной просто улитучились из нашей жизни. |
Автор: Flex Ferrum 01.10.08, 10:56 |
Цитата FireZilla @ Мда, все это хорошо если ты программируеш единственный инструмент - Микропроцессор архитектуры Intel. Нашему же вниманию предлагается международный стандарт на язык программирования для любого типа процессоров и контроллеров. Как бы так сказать, за свою практику я программировал не только Intel, и не только под Windows. А потому возможные проблемы с разным размером типов на разных архитектурах хорошо себе представляю. |
Автор: D_KEY 01.10.08, 11:19 |
Цитата FireZilla @ И вообще у меня сложилось впечатление что комитет стандартизирует не язык программирования, а собсвенно компилятор фирмы Intel. Язык как то начинает быть похожим на ассемблер intel. По всей видимости борьба с коррупцией набриает обороты, броремся так что даже американцы стали берать взятки Ну что за глупости. Конечно, типы гарантированной фиксированной длины были бы не лишними. В том же сетевом программировании это бы очень пригодилось. Но для этого нужны новые типы, а такие типы, как short, int, long специализировать нельзя. И это как раз касается программирования "для любого типа процессоров и контроллеров". Если тебе так уж нужны типы фиксированной длины и хочется обойтись без препроцессора и дополнительных типов компиляторов/системы, то и сейчас можно создать соответствующий список типов и искать в нем тип нужного размера. Господа, а вот по поводу auto вопрос, может кто знает, такой код будет работать? <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template< typename T > class A { public: template< typename Ind > auto operator[]( Ind i ) { return data[i]; } private: T data; }; |
Автор: Flex Ferrum 01.10.08, 11:57 |
Цитата FireZilla @ А касательно finally я скажу просто, если у меня всего одна переменная, зачем тогда мне прибавлять к программе хеадер с 5 000 строк кода Ну, если у тебя всего одна переменная - то проконтролировать ее время жизни и без finally можно. |
Автор: archimed7592 01.10.08, 14:16 |
Думаю, да... Почему бы и нет? Ведь на момент инстанцирования компилятор будет знать тип шаблонного аргумента . |
Автор: D_KEY 02.10.08, 08:47 |
Цитата archimed7592 @ Думаю, да... Почему бы и нет? Ведь на момент инстанцирования компилятор будет знать тип шаблонного аргумента . Да я тоже так "думаю", а вот найти инфу по этому вопросу не могу. Хотя и ищу из рук вон плохо |
Автор: Flex Ferrum 02.10.08, 08:50 |
Цитата archimed7592 @ Кстати, managed C++ - совмещено? Совмещено... Просто плохо и неудобно совмещено Совмещено? Как же, ага. Я как-то попробовал в managed-коде (на MC++) попользоваться шаблонами. Получил по рукам от компилятора, и (в итоге) забросил это дело. Вот так вот оно совмещено было. |
Автор: Qraizer 02.10.08, 09:01 |
А скажите на милось, кто драфт читал, в файловые потоки ввели что-нибудь, позволяющие прицепить поток к уже открытому файлу? Бо уже достало писать что-то вроде <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> и то спасибо MSу и STLPort-у. HANDLE file1; filebuf inFile1; int handle1; file1=CreateFile(pat.second.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if(file1==INVALID_HANDLE_VALUE) { DWORD errCode=GetLastError(); errors.push_back(std::make_pair(errCode, pat.second)); return; } inFile1.open(handle1=_open_osfhandle(reinterpret_cast<int>(file1), _O_RDONLY), std::ios::binary | std::ios::in); if(!inFile1.is_open()) { DWORD errCode=GetLastError(); if(handle1==-1) CloseHandle(file1); else _close(handle1); errors.push_back(std::make_pair(errCode, pat.second)); return; } inFile1.pubsetbuf(&buffer1[0], buffer1.capacity()); /* ... */ if(std::equal(std::istreambuf_iterator<char>(&inFile1), std::istreambuf_iterator<char>(), std::istreambuf_iterator<char>(&inFile2))) break; /* ... */ inFile1.close(); _close(handle1); |
Автор: Flex Ferrum 02.10.08, 09:11 |
Qraizer, а можешь сказать - в каких случаях вообще такое может понадобиться? Мне как-то всегда хватало ifstream/ofstream... |
Автор: archimed7592 02.10.08, 09:11 |
Цитата D_KEY @ Да я тоже так "думаю", а вот найти инфу по этому вопросу не могу. Хотя и ищу из рук вон плохо Цитата 8.3.5/12 A late-specified return type is most useful for a type that would be more complicated to specify before the declarator-id: template <class T, class U> auto add(T t, U u) -> decltype(t + u); rather than template <class T, class U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u); Цитата Flex Ferrum @ Получил по рукам от компилятора, и (в итоге) забросил это дело. Вот так вот оно совмещено было. Всё там отлично пользуется. Другой вопрос, что эти шаблоны не видны из managed кода других сборок(из того же C#) - вот это, да, кривизна совмещения, но, как я уже отметил Цитата archimed7592 @ по понятным причинам - целью было добится какой-нибудь совместимости, а ценою чего эта совместимость достанется никого, видимо, не волновало Что ты подразумеваешь под прицеплением потока к уже открытому файлу? (сорри, код я "слегка" не понял) |
Автор: Flex Ferrum 02.10.08, 09:14 |
Цитата archimed7592 @ Всё там отлично пользуется. Другой вопрос, что эти шаблоны не видны из managed кода других сборок Я имел ввиду Managed C++. А ты, видимо, говоришь про C++/CLI. Добавлено Цитата archimed7592 @ Что ты подразумеваешь под прицеплением потока к уже открытому файлу? (сорри, код я "слегка" не понял) Ну в том смысле, что есть системных хендл открытого файла, и с ним надо ассоциировать STL-ныпоток. |
Автор: archimed7592 02.10.08, 09:24 |
Ммм... мне казалось, что это одно и то же... Разве нет? По крайней мере в студии у меня только один вариант создания .NET/C++ проекта . Цитата Flex Ferrum @ Ну в том смысле, что есть системных хендл открытого файла, и с ним надо ассоциировать STL-ныпоток. Дык, нехрен симстемными хэндлами вообще оперировать - тогда и цеплять ничего никуда не понадобится . |
Автор: Flex Ferrum 02.10.08, 09:26 |
Нет. Managed C++ - это первая инкарнация, которая была в 2003-ей студии. C++/CLI - это "с учетом недоработок и недоделок", а по сути - совсем другая реализация. |
Автор: archimed7592 02.10.08, 09:28 |
Цитата Flex Ferrum @ Нет. Managed C++ - это первая инкарнация, которая была в 2003-ей студии. C++/CLI - это "с учетом недоработок и недоделок", а по сути - совсем другая реализация. Ааа... А я всегда думал, что это два разных названия одного и того же. Не, первую инкарнацию я видел, но юзать побоялся . Суть моего высказывания не меняется - замени manager C++ на C++/CLI . BTW, на С++/CLI чуть ли не стандарт есть(или готовится), если я не ошибаюсь. |
Автор: Qraizer 02.10.08, 12:23 |
Цитата archimed7592 @ А приходится иногда. В приведённом примере, впрочем, это неактуально. Поток тут хорош был тем, что STLPort для бинарно открытого файла заюзывает memory-mapped, плюс бинарное сравнение файлов элементарным алгоритмом std::equal. Ну а файл открывался виндой всего лишь ради ключика FILE_FLAG_SEQUENTIAL_SCAN. Но вот понадобиться мне кастомный security descriptor присобачить, на пример в сервисе... Всё, STL побоку по-любому. Дык, нехрен симстемными хэндлами вообще оперировать - тогда и цеплять ничего никуда не понадобится |
Автор: Flex Ferrum 28.10.08, 14:42 |
Хех. Кто хочет попробовать новые фишки стандарта в исполнении от Microsoft - качайте Microsoft Visual Studio 2010 Community Technology Preview. Обещают лямбды, auto, static assert. Более детальной информации по нововведениям пока найти не могу. Добавлено Эээ... Забыл предупредить. Качать придется от половины до семи гигов, т. к. CTP идет в виде образа для Virtual PC. |
Автор: Flex Ferrum 28.10.08, 17:26 |
Собственно, в соседней теме подсказали источник подробностей: http://blogs.msdn.com/vcblog/archive/2008/...c10-part-1.aspx |
Автор: Flex Ferrum 29.10.08, 17:41 |
Кстати, по поводу лямбд в gcc. На самом деле, уже не так плохо: Цитата 1. Lambda expressions can be passed to function templates, and are usable with the std::CallableN class of concepts. 2. A lambda function can be defined wherever a primary-expression is expected. 3. Default capture allows a lambda function to use external variables without first declaring them. An equals sign (=) means to store such captures by-copy; an ampersand (&) means by-reference. 4. However, each capture and its storage mechanism may be explicitly declared. In this context, an unadorned name means by-copy; an ampersand (&) means by-reference. 5. Initializer expressions, an extension to the proposal, are supported. 6. Argument types must be explicitly annotated. 7. The body must be a compound-statement. Additional features include: * When used inside a member function, a lambda o can capture this explicitly, or by default when it uses direct or indirect references to class members. o has private access to the class. Bugs * Return type deduction is currently broken. * Although they can appear within templates, lambda functions may not be used with dependent types. Взято отсюда: http://parasol.tamu.edu/groups/pttlgroup/lambda/ |
Автор: maggot 30.10.08, 18:51 |
Цитата It has been suggested to (re)use the keyword typedefas done in the paper [4] to introduce template aliases: template<class T> typedef std::vector<T, MyAllocator<T> > Vec; That notation has the advantage of using a keyword already known to introduce a type alias. However, it also displays several disavantages among which the confusion of using a keyword known to introduce an alias for a type-name in a context where the alias does not designate a type, but a template; Vec is not an alias for a type, and should not be taken for a typedef-name. The name Vec is a name for the family std::vector< , MyAllocator< > > where the bullet is a placeholder for a type-name. Consequently we do not propose the typedef syntax. On the other hand the sentence template<class T> using Vec = std::vector<T, MyAllocator<T> >; can be read/interpreted as: from now on, I'll be using Vec<T> as a synonym for std::vector<T, MyAllocator<T> >. With that reading, the new syntax for aliasing seems reasonably logical. Кто-нибудь может на пальцах объяснить, чем Алиасы лучше typedef templates? |
Автор: archimed7592 31.10.08, 00:07 |
Ummm... В приведённой тобой цитате "лучше" и "хуже" они только в плане "читабельности". В остальном они эквивалентны. |
Автор: n0rd 12.11.08, 19:48 |
Доклад про Concepts. 1 час видео. |
Автор: gpd 21.11.08, 09:58 |
Вам не кажется, что новым стандартом никто не будет пользоваться? Что язык будет слишком сложный? То есть для него никогда не будут созданы средства рефакторинга, анализа кода. Время обучения языку гараздо выше чем у многих других ныне популярных языков. Кому это нужно? Ведь на Java или С можно делать всё то же самое. Такое чувство, что новый стандарт приведет к тому, что C++0x будет чисто академическим языком. По-моему двигаться нужно в сторону упрощения языка, а не усложнения. Я лет 5 назад был сторонником С++ и думал что у него есть будущее. Но похоже с новым стандартом на С++ можно положить крест. |
Автор: Qraizer 21.11.08, 13:28 |
Мне не кажется. Кое-что из нового жду с нетерпением, те же концепты, r-value ссылки и auto, к примеру. Думаю, что на осиливание нового в языке уйдёт порядка месяца, нового в библиотеке - раза в 2-3 больше. Это с учётом того, что boost в общем-то знаком. Так что лично для себя не вижу проблем. Сильно сложнее он в новом стандарте не становится, а вот удобнее становится заметно. |
Автор: kanes 21.11.08, 13:31 |
А это который раньше в Си был или я что-то путаю? |
Автор: Dantes 21.11.08, 13:43 |
Забавное предположение Нет, нельзя. За счёт усложнения языка достигается упрощение программирования. Упрощение языка приведёт к обратному эффекту. Цитата gpd @ Я лет 5 назад был сторонником С++ и думал что у него есть будущее. Но похоже с новым стандартом на С++ можно положить крест. К счастью, C++ не нуждается в таких сторонниках Гораздо выгоднее изучить сложную технологию, чем постоянно самостоятельно возиться над решением мелких проблем, тривиально решаемых с помощью этой технологии. Полагаю, всему прогрессивному человечеству данная прописная истина должна быть хорошо известна. |
Автор: Qraizer 21.11.08, 14:21 |
kanes, ну, как бы да, но в новом стандарте auto из пешки превращается... если не в ферзя, то в ладью точно. Dantes, как-то резко ты в конце... Или мне показалось? |
Автор: kanes 21.11.08, 14:23 |
Цитата Qraizer @ ну, как бы да, но в новом стандарте auto из пешки превращается... если не в ферзя, то в ладью точно. А можно по подробней об этом? Пожалуйста |
Автор: archimed7592 21.11.08, 14:27 |
Первый пост, поиск по предложению Цитата Deducing the type of variable from its initializer expression. Добавлено Аналог var из C#(или var в C# - аналог auto ). |
Автор: miksayer 21.11.08, 16:09 |
а для тех, кто не знает C# можно поподробнее? |
Автор: kanes 21.11.08, 16:25 |
Переменная, определённая под этим ключевым словом автоматически приобретёт тип при инциализации. Если я правильно понимаю новый смысл auto Добавлено Например: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> auto y = 10.0; // y — это число с плавающей точкой const auto *p = &y; // p является const double * |
Автор: archimed7592 21.11.08, 16:33 |
Скорее для тех, кто ленится прочитать уже не один раз написанное(в этой теме). Ок. Было: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> SomeNamespace::WithInnerNamespace::SomeVeryLongTypeName *obj = new SomeNamespace::WithInnerNamespace::SomeVeryLongTypeName(); Стало: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> auto *obj = new SomeNamespace::WithInnerNamespace::SomeVeryLongTypeName(); Это, на самом деле, самый примитивный случай. Более интересные ситуации не решаемы копипастом. |
Автор: amk 21.11.08, 18:40 |
В-общем, auto позволит в некоторых случаях сократить количество набиваемых символов, вместо <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> можно будет написать более короткое & for (std::vector<SomeType>::iterator i = myvector.begin(); i != myvector.end(); ++i) { ... } <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> А какого еще типа может быть i?for (auto i = myvector.begin(); i != myvector.end(); ++i) { ... } Вдобавок, позволит повысить гибкость шаблонов. Не обязательно будет так длинно описывать каждый возвращаемый тип (Точнее можно будет использовать не так строго определенные классы) ИМХО, очень полезное изменение. |
Автор: Qraizer 21.11.08, 19:04 |
Вот один из очень таких интересных случаев: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> #include <complex> template <typename L, typename R> std::complex<decltype(L()+R())> operator+(const std::complex<L>& l, const std::complex<R>& r) { auto re = l.real()+r.real(); auto im = l.imag()+r.imag(); return std::complex<decltype(re)>(re, im); } |
Автор: max_f 21.11.08, 21:42 |
А пересылку в шаблонах можно будет делать? Если упрощенно, то что-нибудь такое: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template< typename T > class A { public: auto f() { return a.g(); } private: T a; }; // class A А то сейчас подобного поведения добиться вообще никак нельзя(или я пока слабоват в метапрограмминге). |
Автор: trainer 23.11.08, 07:01 |
Одно из предполагаемых предназначений auto - определение типа результата функции на основании типа аргумента return. Правда неясен вопрос с несколькими return в функции, из-за чего эта возможность может быть и не включена. |
Автор: Flex Ferrum 23.11.08, 12:24 |
Цитата trainer @ Правда неясен вопрос с несколькими return в функции, из-за чего эта возможность может быть и не включена. Вполне может разруливаться путем ошибки компиляции. Т. е. компилятор потребует от программиста привести все return'ы к одному типу. |
Автор: Dantes 23.11.08, 15:10 |
Цитата Flex Ferrum @ Т. е. компилятор потребует от программиста привести все return'ы к одному типу. Возможно и менее строгое требование - существование общего типа, как у операндов тернарного оператора <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> auto f(bool b) { if (b) return 1; else return 2.5; // поведение аналогично return b ? 1 : 2.5; } |
Автор: amk 24.11.08, 17:34 |
Правда чтобы воспользоваться таким определением нужно видеть тело функции, то есть практически только для определения inline-функций и шаблонных. |
Автор: D_KEY 24.11.08, 20:32 |
Цитата Dantes @ Цитата Flex Ferrum @ Т. е. компилятор потребует от программиста привести все return'ы к одному типу. Возможно и менее строгое требование - существование общего типа, как у операндов тернарного оператора <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> auto f(bool b) { if (b) return 1; else return 2.5; // поведение аналогично return b ? 1 : 2.5; } Тип результата тернарного оператора определяется не "общем типом"(что это, кстати?), а типом последнего варианта... |
Автор: Dantes 25.11.08, 11:14 |
Цитата D_KEY @ Тип результата тернарного оператора определяется не "общем типом"(что это, кстати?), а типом последнего варианта... Тип его результата определяется правилами в пункте 5.16 стандарта. В стандарте нет термина common type, но такое словосочетание там присутствует, и что оно означает, по-моему, вполне очевидно. |
Автор: slavik_xxx 03.12.08, 10:19 |
Да... Язык скатывается в яму маразма. Количества правил, крючков и их сочетаний увеличивается. Ясность чтения уменьшается. |
Автор: D_KEY 06.12.08, 11:22 |
Цитата slavik_xxx @ Да... Язык скатывается в яму маразма. Количества правил, крючков и их сочетаний увеличивается. Ясность чтения уменьшается. Фразы такого рода преследуют С++ с рождения . На мой взгляд язык становится даже проще в использовании и логичнее, а возможности его возрастают. А если тебе не ясны какие-то "крючки" и "их сочетания" ты можешь их не использовать. "Что не использую, за то не плачу"... |
Автор: Большой 08.12.08, 10:59 |
с позиции практики, а с позиции теории. Ведь студентам тогда придется учить еще больше |
Автор: Flex Ferrum 08.12.08, 11:06 |
Цитата Большой @ с позиции практики, а с позиции теории. Ведь студентам тогда придется учить еще больше Хм. Боюсь, типичный студент несколько, гм, слабоват для изучения "теории" С++. По этому "больше" ему учить не придется. |
Автор: Большой 08.12.08, 11:49 |
Меня просто радует вот эта фича <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> auto func(int x) -> double {return pow(x);} т.е если раньше стандартом запрещено было создавать две функции с одинаковыми сигнатурами <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> int func(int x); double func(int x); так теперь все норма компилер сам будет соображать с auto(ну если компилер совсем будет слаб то ему подсунем, что тип возращаемого значения желательно double, наверное как и с inline он еще подумает делать его double или лучше int) Интересно в новом стандарте эти 2 функции будут с разными сигнатурами или нет? |
Автор: amk 08.12.08, 17:57 |
Сигнатура будет одна, и компилятор скорее всего не позволит тебе их создать. Просто можно будет не указывать тип возврата. Компилятор сам сообразит. А типы параметров ты все равно укажешь. |
Автор: Большой 09.12.08, 10:15 |
а когда ожидать пришествия нового стандарта? |
Автор: B.V. 15.12.08, 08:03 |
Цитата Википедия Комитет Стандартизации C++ намеревается опубликовать новый стандарт в 2009 |
Автор: Большой 18.12.08, 09:26 |
B.V. Я слышал вроде бы в конце этого года комитет на Гаваях будет зажигать и только после этого будет принят новый стандарт. Известно ли будет typeof в стандарте или нет? |
Автор: LuckLess 18.12.08, 09:46 |
насет typeof не знаю, но вот auto будет.. (а имхо auto - заменитель typeof..) |
Автор: Большой 18.12.08, 09:51 |
Вычодит auto панацея от всех бед |
Автор: archimed7592 18.12.08, 10:52 |
Будет, только название "другое" будет иметь: decltype(...). В "длинных" постах в этой теме всё написано . |
Автор: Большой 18.12.08, 16:32 |
archimed7592 мне кажется запомнить лучше typeof чем decltype decltype сокращение от declaration type или нет? |
Автор: archimed7592 19.12.08, 02:47 |
Насчёт лучше - сомневаюсь. Насчёт проще запомнить - ну, возможно. Именно. |
Автор: Qraizer 19.12.08, 14:16 |
Думаю, что "переименование" typeof в decltype вызвано отсутствием желания сделать кучу реализаций, которые поддерживали typeof как расширение языка, несовместимыми с новым стандартом. Кроме того, семантика decltype всё-таки чуток отличается от семантики typeof, или я не прав? |
Автор: archimed7592 19.12.08, 14:30 |
Цитата Qraizer @ Кроме того, семантика decltype всё-таки чуток отличается от семантики typeof, или я не прав? Для начала нужно определиться с тем, что мы понимаем под "семантикой typeof", тогда можно будет поговорить об отличиях от семантики decltype . Цитата Qraizer @ Думаю, что "переименование" typeof в decltype вызвано отсутствием желания сделать кучу реализаций, которые поддерживали typeof как расширение языка, несовместимыми с новым стандартом. Не знаю, в вопрос особо не вдавался, но очень частая причина заключается в том, что при именовании сущностей(и, в особенности, ключевых слов), дабы минимизировать количество сломанного кода, комитет пользуется гуглём. В нашем случае различие в количестве результатов на порядок(typeof(25000) vs decltype(2000)). |
Автор: Qraizer 19.12.08, 15:10 |
Цитата archimed7592 @ А я и не знаю этого typeof-а. Слышал - да. Но то, что слышал не коррелирует с decltype. Вот и сделал вывод. Для начала нужно определиться с тем, что мы понимаем под "семантикой typeof", тогда можно будет поговорить об отличиях от семантики decltype . |
Автор: archimed7592 19.12.08, 15:50 |
Чего слышал то? |
Автор: Qraizer 19.12.08, 16:24 |
Блин, трижды обновлял страничку в ответ на "сервер недоступен", получил три поста. Ну, что typeof имеет семантику применения результата typedef. В новом же стандарте decltype имеет больше возможностей. Нет? |
Автор: archimed7592 19.12.08, 16:36 |
Цитата Qraizer @ Ну, что typeof имеет семантику применения результата typedef. В новом же стандарте decltype имеет больше возможностей. Нет? Хм... Т.е. с твоих слов, decltype можно применять где-то где нельзя применять результат typedef и/или семантика применения decltype где-то будет как-то отличаться от применения результата typedef... Можно увидеть примеры? |
Автор: Qraizer 19.12.08, 17:08 |
Не, не то. Результатом typeof(expr) является тип результата выражения expr. И если typeof встречается где-то в программе, семантически это будет эквивалентным тому, как если бы где-то был записан typedef, который каким-нибудь идентификатором именует этот самый тип результата expr, а на месте typeof стоял этот самый идентификатор, ведённый typedef-ом. Я так считал. Но возможно, что считал неправильно, потому как не юзал никогда typeof из-за его непереносимости. Почитав же о decltype, я сложил мнение, что они неэквивалентны. |
Автор: archimed7592 19.12.08, 18:23 |
В каком месте? Ну, можешь считать, что где-то появляется typedef с уникальным именем. Можешь считать, что просто вместо выражения typeof/decltype подставляется тип. Семантически разница в чем заключается? |
Автор: Qraizer 20.12.08, 14:58 |
Ну так я об этом и спрашивал. "Всё что знал, всё сказал" ©, а дальше был вопрос Цитата Qraizer @ В драфте decltype описывается бо́льшим количеством пунктов. Кроме того, семантика decltype всё-таки чуток отличается от семантики typeof, или я не прав? |
Автор: archimed7592 20.12.08, 15:56 |
Ну, в той степени, в которой ты раскрыл семантику typeof - нет, семантика decltype ничем не отличается . |
Автор: Большой 24.12.08, 06:02 |
David Vandevoorde and Nicolai M. Josuttis Пишут о typeof следующее При написании шаблонов часто полезно иметь возможность указать тип выражения, зависящего от шаблона. Наглядным примером такой ситуации является объявление арифметической операции для шаблона числового массива, в котором типы операндов различны. Следующий пример должен прояснить данную мысль: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <typename Tl, typename T2> Array<???> operator+(Array<Tl>const& x, Array<T2>const& y); Предположительно эта операция должна создать массив элементов, которые являются результатом сложения соответствующих элементов массивов х и у. Таким образом, результирующий элемент будет иметь тип х [0] +у [0]. К сожалению, в языке C++ отсутствует надежный способ выражения этого типа с помощью Т1 и Т2. В качестве расширения, направленного на решение этого вопроса, в некоторых компиляторах имеется операция typeof. Она напоминает операцию sizeof тем, что позволяет получить из исходного выражения некоторый объект времени компиляции, но в данном случае этот объект может выступать в качестве имени типа. Тогда предыдущий пример можно записать следующим образом: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <typename Tl, typename T2> Array<typeof(Tl()+T2())> operator + (Array<Tl> const& x, Array<T2> const& y); Очень даже неплохо, но не идеально. Действительно, здесь предполагается, что данные типы могут быть инициализированы по умолчанию. Это можно обойти, вводя вспомогательный шаблон. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <typename T> Т makeTO; // Определение не требуется template <typename Tl, typename T2> Array<typeof(makeT<Tl>()+makeT<T2>() ) > operator + (Array<Tl> const& x, Array<T2> const& y); В аргументе typeof мы бы предпочли использовать х и у, но не можем этого сделать, так как они не были объявлены в точке расположения конструкции typeof. Радикальное решение этой проблемы заключается в том, чтобы ввести альтернативный синтаксис объявления функции, в котором возвращаемый тип помещается после параметров. // Шаблон функции оператора: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <typename Tl, typename T2> operator + (Array<Tl> constfc x, Array<T2> constfc y) -> Array< typeo f(x+y)>; // Шаблон регулярной функции: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <typename Tl, typename T2> function exp(Array<Tl> const& x, Array<T2> const& y) -> Array<typeof(exp(x,y))> Как видно из этого примера, новый синтаксис для неоператорных функций включает новое ключевое слово, в данном случае— function (чтобы выполнить процесс синтаксического анализа для операторных функций, достаточно ключевого слова operator). Обратите внимание, что операция typeof должна быть операцией времени компиляции. В частности, как видно из следующего примера, операция typeof не принимает во внимание ковариантные возвращаемые типы. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> class Base { public: virtual Base clone(); }; class Derived : public Base { public: virtual Derived clone(); // Ковариантный возвращаемый тип }; void demo (Base* p, Base* q) { typeof(p->clone()) tmp = p->clone(); ( // tmp всегда будет иметь тип Base } |
Автор: Qraizer 24.12.08, 14:43 |
Большой, классная книжка. Я не видел другой, также подробно описывающей шаблоны. |
Автор: Большой 06.01.09, 09:42 |
Известно,что в STL отсутствует алгоритм copy_if будет ли он в новом стандарте и вооще какие будут еще алгоритмы если будут конечно. |
Автор: archimed7592 06.01.09, 09:46 |
Really? Мне неизвестно . Посмотри на remove_copy_if. Думаю, это - как раз то, что ты понимаешь под copy_if. |
Автор: Большой 06.01.09, 09:48 |
archimed7592 а вот мейерс утверждает, что нет |
Автор: archimed7592 06.01.09, 10:12 |
Извини, я не совсем понимаю, что именно он утверждает? То, что нет алгоритма копирования последовательности с заданным фильтром? Если да, то хотелось бы увидеть его слова дословно и в оригинале . |
Автор: Большой 06.01.09, 13:09 |
С. Мейерс "Эффективное использование STL" совет 36. Правильно используйте copy_if В STL имеется 11 алгоритмов, в именах которых присутствует слово сору. Но как ни странно, алгоритма copy_if среди них нет. Таким образом, вы можете вызывать replace_copy_if и remove_copy_if, к вашим услугам copy_backward и reverse_copy, но если вдруг потребуется просто скопировать элементы интервала, удовлетворяющие определенному предикату, вам придется действовать самостоятельно. Добавлено archimed7592 Хотя меня больше интересуют новые алгоритмы |
Автор: archimed7592 06.01.09, 13:25 |
Большой, по поводу copy_if - смешно . Непонятно, как это у Мейрса оказалось... Суть в том, что в STL отсутсвует великое множество алгоритмов, которые могли бы быть очень полезны(как copy_if, к примеру), но присутсвуют кирпичики из которых все эти полезные алгоритмы можно построить. Тот же copy_if который имеет ввиду Мейрс - это remove_copy_if с отрицанием предиката(я уверен, далее по тексту это упоминается). Добавлено Появились новые алгоритмы, модифицировались "старые"(в сторону поддержки концептов, rvalue references, intializers). Если интересуют подробности, то можешь скачать текущий черновик(который по сути является почти чистовиком) и сравнить с версией 2003 года. Версия 2003 года лежит в FAQ, последний черновик - на open-std.org. Раздел 25 Algorithms library. |
Автор: Большой 15.01.09, 09:02 |
archimed7592 Да разобрался оказывается transorm общий случай копирования с условием. А что такое Atomic operations library и с чем его едят? |
Автор: archimed7592 15.01.09, 13:38 |
Библиотека для совершения атомарных операций . Едят с многопоточностью. |
Автор: Большой 15.01.09, 18:49 |
а как ? мона небольшой пример. плизззз |
Автор: amatros 15.01.09, 21:03 |
Цитата Большой @ Вот и вот, прямо из кухни шеф-повара |
Автор: Большой 09.02.09, 13:25 |
Что-то в рабочем дравте не нашел Prohibited access specifier Значит не будет? |
Автор: Masterkent 09.02.09, 19:19 |
Видимо, не будет. Будут deleted определения. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct X { X(X &) = delete; // запрет на использование копирующего конструктора void operator =(X) = delete; // запрет на использование копирующего оператора присваивания }; |
Автор: Большой 18.02.09, 12:50 |
Masterkent а default, что значит? |
Автор: archimed7592 18.02.09, 14:45 |
Большой, см первый пост, поиск по заголовку "Defaulted and Deleted Functions". Или у тебя более конкретный вопрос есть? |
Автор: Большой 19.02.09, 09:48 |
archimed7592 почитал совершенно непонятно. Единственное что понял, что default функции можно реализовывать как непосредственно в определении класса так и в не его. Возможно default значит, что компилятор должен использовать "свои" версии функций обычно реализованные компилятором если пользователь их не определяет. Или это значит что-то иное? |
Автор: archimed7592 19.02.09, 14:58 |
Большой, ну, к примеру, ты не хочешь модифицировать тело деструктора, но ты хочешь сделать его виртуальным: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct X { virtual ~X() = default; } Цитата Большой @ Возможно default значит, что компилятор должен использовать "свои" версии функций обычно реализованные компилятором если пользователь их не определяет. Дело в том, что если пользователь их не определяет, то компилятор и так воспользуется "своими" реализациями. Другое дело, когда пользователь их определяет - иногда, пользователю действительно необходимо определить свою версию деструктора(к примеру), но когда у него нет необходимости определять свой деструктор, а добавить виртуальность или изменить модификатор доступа(private/protected/public) хочется - тогда он может и сообщить компилятору о необходимых изменениях и оставить за компилятором реализацию по умолчанию. К примеру, если есть желание сделать конструктор копирования protected, то можно увидеть разницу в количестве кода и потенциальной ошибке при добавлении новых полей и НЕредактировании конструктора: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // C++03 struct X : B1, B2, ..., Bn { T1 f1; T2 f2; // ... Tn fn; protected: X(const X ©) : B1(copy), B2(copy), ..., Bn(copy), f1(copy.f1), f2(copy.f2), ..., fn(copy.fn) { } } // C++09 struct X : B1, B2, ..., Bn { T1 f1; T2 f2; // ... Tn fn; protected: X(const X ©) = default; } Заметь, при добавлении поля fn+1 или базового класса Bn+1 ничего редактировать в конструкторе не придётся. |
Автор: Большой 19.02.09, 22:35 |
archimed7592 все равно не понятно а не проще тогда вообще не писать конструктор копирования (в этом случае компилер создаст свой конструктор копирования, работающего по принципу побитового копирования ) |
Автор: Flex Ferrum 19.02.09, 22:36 |
Цитата Большой @ все равно не понятно а не проще тогда вообще не писать конструктор копирования (в этом случае компилер создаст свой конструктор копирования, работающего по принципу побитового копирования ) Во-первых, не побитового, а поэлементного, а во-вторых - нет, не проще, т. к. в данном случае (если ты обратишь внимание) требование - чтобы конструктор бы protected. А компилятор по умолчанию сгенерирует public. Понятна разница? |
Автор: Большой 19.02.09, 22:39 |
Цитата archimed7592 @ Большой, ну, к примеру, ты не хочешь модифицировать тело деструктора, но ты хочешь сделать его виртуальным: с этим понятно, а с конструктором копий нет Добавлено Саттер пишет что побитовое, а с конструктором копий понятно, не сразу обратил внимание на protected |
Автор: archimed7592 19.02.09, 22:45 |
Нужно, чтобы "конструктор копий" был protected. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct A { }; struct B { protected: B(const B ©) = default; }; int main() { A a1; A a2 = a1; // OK B b1; B b2 = b1; // error } Понятно, что будет, если "вообще не писать конструктор копирования"? |
Автор: Большой 19.02.09, 22:56 |
А если попробовать так? <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct A { A(int _a) {} A()=default; }; будет работать? |
Автор: archimed7592 19.02.09, 22:57 |
Что именно? |
Автор: Большой 19.02.09, 23:00 |
ну первый и второй конструктор |
Автор: archimed7592 19.02.09, 23:03 |
Ну да. Кстати говоря - вот тебе ещё одно применение default. |
Автор: Большой 19.02.09, 23:06 |
archimed7592 Вот об этом я и подумал, тогда очень хорошо |
Автор: Большой 24.02.09, 07:09 |
а реализации адаптеров типа compose1 и compose2 реализованные в STL от SGI и ряда других. Не будет? Поискал в драфте ничего не нашел или не там искал? |
Автор: Flex Ferrum 24.02.09, 07:17 |
Цитата Большой @ а реализации адаптеров типа compose1 и compose2 реализованные в STL от SGI и ряда других. Не будет? А зачем, если теперь будет bind? |
Автор: Большой 24.02.09, 07:49 |
Flex Ferrum Он полностью из boost а всякие bind2sd для совместимости оставили? |
Автор: Flex Ferrum 24.02.09, 07:52 |
Вроде да. |
Автор: Большой 25.02.09, 11:39 |
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct A { double x; }; const A* a = new A(); Почему здесь type is double <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> decltype(a->x) x3; а здесь type is const double& <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> decltype((a->x)) x4; Добавлено и в этом случае не разобрался <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <class T, class U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u); что это? <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> decltype((*(T*)0) + (*(U*)0)) |
Автор: archimed7592 25.02.09, 14:15 |
Большой, ты о чём? Откуда эти выкладки? Ссылку хоть дай. |
Автор: Masterkent 25.02.09, 15:19 |
Цитата Большой @ <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct A { double x; }; const A* a = new A(); Почему здесь type is double <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> decltype(a->x) x3; а здесь type is const double& <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> decltype((a->x)) x4; Существует разница между типом объявленной сущности и типом выражения, в котором эта сущность участвует. Также существует разница между типом возврата функции и типом выражения, представляющего собой вызов этой функции. Например, здесь <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> int i; int &ri = i; int f(); int &g(); int &&h(); struct A { int x; }; const A* a = new A(); decltype(i) x1; // int (i - id-expression) decltype((i)) x2; // int & decltype(ri) x4; // int & (ri - id-expression) decltype((ri)) x5; // int & decltype(f()) x6; // int (f() - function call) decltype((f())) x7; // int (f() - function call) decltype(g()) x8; // int & (g() - function call) decltype((g())) x9; // int & (g() - function call) decltype(h()) x10; // int && (h() - function call) decltype((h())) x11; // int && (h() - function call) decltype(a->x) x12; // int (a->x - class member access) decltype((a->x)) x13; // const int & тип объявленной сущности (переменной) i - это int, тип выражения i - это int, тип объявленной сущности (ссылки) ri - int &, тип выражения ri - int, тип возврата f - int, тип выражения f() - int, тип возврата g - int &, тип выражения g() - int, тип возврата h - int &&, тип выражения h() - int, тип объявленной сущности A::x - int, тип выражения a->x - const int. Помимо типа, у всякого выражения есть дополнительная характеристика - это принадлежность к lvalue или rvalue. Например, выражения i, ri и g() в примере выше - это lvalue, а f() и h() - это rvalue. decltype даёт возможность выяснить как тип объявленной сущности или тип возврата функции, так и тип выражения вместе с принадлежностью его к lvalue или rvalue. Если в качестве аргумента e указывается id-expression или class member access, то результат decltype(e) обозначает тип соответствующей объявленной сущности. При этом выражение e имеет тип std::remove_reference<decltype((e))>::type и является lvalue, если std::is_lvalue_reference<decltype((e))>::value равно true. Если в качестве аргумента указывается вызов функции или вовлечение перегруженного оператора (круглые скобки вокруг будут игнорироваться), то результат decltype обозначает тип возврата функции, выбранной для вызова. При этом выражение e имеет тип std::remove_reference<decltype(e)>::type и является lvalue, если std::is_lvalue_reference<decltype(e)>::value равно true. Обычно выяснять тип и принадлежность к lvalue поотдельности не требуется, т.е. результат decltype в большинстве случаев будет использоваться без каких-либо дополнительных манипуляций с ним. Цитата Большой @ и в этом случае не разобрался <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <class T, class U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u); что это? <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> decltype((*(T*)0) + (*(U*)0)) Здесь определяется тип суммы двух слагаемых, одно из которых - lvalue типа T, а другое - lvalue типа U. При определении типа аргумента decltype учитываются типы и принадлежность к lvalue подвыражений, из которых он состоит (при этом сами подвыражения не вычисляются). Имеем: выражение (T*)0 - rvalue типа T* (в данном случае принадлежность к lvalue/rvalue ни на что не влияет), выражение *(T*)0 - lvalue типа T выражение (U*)0 - rvalue типа U* (в данном случае принадлежность к lvalue/rvalue ни на что не влияет), выражение *(U*)0 - lvalue типа U выражение (*(T*)0) + (*(U*)0) имеет тот же тип и ту же принадлежность к lvalue/rvalue, что и t + u. Добавлено Видимо, из черновика стандарта: Цитата N2798 7.1.6.2 Simple type specifiers / 4 The type denoted by decltype(e) is defined as follows: — if e is an id-expression or a class member access (5.2.5), decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed; — otherwise, if e is a function call (5.2.2) or an invocation of an overloaded operator (parentheses around e are ignored), decltype(e) is the return type of that the statically chosen function; — otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e; — otherwise, decltype(e) is the type of e. The operand of the decltype specifier is an unevaluated operand (Clause 5). [ Example: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> —end example ]const int&& foo(); int i; struct A { double x; }; const A* a = new A(); decltype(foo()) x1; // type is const int&& decltype(i) x2; // type is int decltype(a->x) x3; // type is double decltype((a->x)) x4; // type is const double& |
Автор: Большой 25.02.09, 18:52 |
из рабочего черновика |
Автор: Большой 26.02.09, 08:54 |
Masterkent decltype() - что это вообще? тип, функция, оператор? наверное врыжение результатом которого является тип. Чтобы мозг зацепился за понятие этой темы необходимо это знать. |
Автор: archimed7592 26.02.09, 10:31 |
Автор: Masterkent 27.02.09, 20:36 |
decltype(expression) - это спецификатор типа, обозначающий тип Какой именно тип он обозначает, определяется правилами в 7.1.6.2/4. Типы не являются выражениями, поэтому decltype(expression) - это не выражение. |
Автор: Большой 04.03.09, 08:24 |
почему? |
Автор: Masterkent 04.03.09, 12:38 |
Потому что это подходит под 3-й случай: Цитата The type denoted by decltype(e) is defined as follows: — if e is an id-expression or a class member access (5.2.5), decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed; — otherwise, if e is a function call (5.2.2) or an invocation of an overloaded operator (parentheses around e are ignored), decltype(e) is the return type of that the statically chosen function; — otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e; — otherwise, decltype(e) is the type of e. lvalue-ссылка здесь показывает, что выражение является lvalue, а не rvalue. Аналогичное соглашение используется для типа возврата из функции: результатом вызова функции является lvalue, если тип возврата является lvalue-ссылкой, иначе результатом будет rvalue. Таким образом, decltype может быть использован в записи типа возвращаемого значения. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> int i; enum { e }; // возвращает оригинальный объект i по lvalue-ссылке decltype(i) get_i() { return i; } // возвращает временный объект, равный e; // e не является lvalue и не может быть возвращено по lvalue-ссылке decltype(e) get_e() { return e; } |
Автор: Большой 05.03.09, 06:00 |
Masterkent т.е. (i) интерпритируется как вызов функции? |
Автор: archimed7592 05.03.09, 06:59 |
Нет, как lvalue expression, т.е. выражение, которое может стоять слева от оператора присваивания. Отличие (i) от i в том, что i - это переменная, к примеру, а (i) - это выражение. |
Автор: Большой 06.03.09, 12:28 |
что такое "derived-declarator-type-list" ? в составе "derived-declarator-type-list T" или "derived-declarator-type-list reference to T" В предложении <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> In a declaration T D where D has either of the forms & D1 && D1 and the type of the identifer in the declaration T D1 is “derived-declarator-type-list T,” then the type of the identi?er of D is “derived-declarator-type-list reference to T.” |
Автор: Flex Ferrum 01.04.09, 07:01 |
Так, ну вот. Зарелизили gcc 4.4.0. Из вкусностей C++0x, которые можно попробовать: - Extending variadic template template parameters - Initializer lists - auto-typed variables (!!!) - Removal of auto as a storage-class specifier - New function declarator syntax (в рамках auto) - Solving the SFINAE problem for expressions - Strongly-typed enums - Defaulted and deleted functions - Inline namespaces В качестве отдельных патчей: - Delegating constructors - Lambda expressions and closures - Concepts (последние два - в активной разработке). Любителям TDM-сборок MinGW придется немножко подождать... Сколько - не известно... |
Автор: Большой 09.04.09, 07:57 |
что-то я не вижу разницы между этими двумя объявлениями или упустил что-то из виду? |
Автор: Большой 09.04.09, 18:47 |
Цитата archimed7592 @ 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 & непонял а почему int& а не просто int |
Автор: pan2004 13.04.09, 09:38 |
Цитата Flex Ferrum @ Зарелизили gcc 4.4.0. ... В качестве отдельных патчей: - Delegating constructors - Lambda expressions and closures - Concepts Известно когда их с основной веткой объединят? Особенно lambda интересует. |
Автор: Большой 13.04.09, 11:08 |
archimed7592 Проверил под COdegear 2009 <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> void g(long & a1) { ++a1; } template<class A1> void f(A1 && a1) { g(static_cast<A1 &&>(a1)); } <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> long i = 5; g(i); f(i); //7 f<long>(i); //8 f<long&>(i); //9 f<long&&>(i); //10 Ответ для всех версий одинаков в переменной i всегда инкрементируемое значение |
Автор: archimed7592 13.04.09, 11:20 |
Так и должно быть. Это же forwarding. Представь, что ты каждый раз вызываешь g. |
Автор: доцент 22.04.09, 17:46 |
archimed7592 Интересно звучит, а понять как? |
Автор: Леголегс 30.04.09, 13:13 |
Кто разобрался в новом стандарте, поясните. Я правильно пинимаю, что rvalue-ссылки позволяют создавать операторы переноса operator=(T && t) в дополнение к операторам копирования operator=(const T & t) и как только такое будет реализовано для контейнеров стандартной библиотеки код типа нижеприведённого резко ускорится без модификаций? <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> vector < vector<char> > vv; vv.push_back(vector<char>(100000)); |
Автор: Flex Ferrum 30.04.09, 13:18 |
Цитата Леголегс @ Кто разобрался в новом стандарте, поясните. Я правильно пинимаю, что rvalue-ссылки позволяют создавать операторы переноса operator=(T && t) в дополнение к операторам копирования operator=(const T & t) и как только такое будет реализовано для контейнеров стандартной библиотеки код типа нижеприведённого резко ускорится без модификаций? По-идее, да. |
Автор: mas912 01.05.09, 07:45 |
Цитата Flex Ferrum @ Любителям TDM-сборок MinGW придется немножко подождать... Сколько - не известно.. GCC 4.4.0 для винды, сам гцц, без всего пакета mingw. Но для поиграться или отладить что-то по-быстрому самое то. Вот это и меня интересует. И вообще, может кто в курсе плана развития гцц? Типа, что будет в след. версии, когда и тюпю. Вот, кстати, ссылка на состояние поддержки С++0х в различных компиляторах: тыц. Познавательно. Хотя мне непонятно, почему никто до сих пор не поддерживает nullptr. |
Автор: Большой 10.05.09, 11:50 |
Похоже стандарт только в 2011 году появится |
Автор: mas912 12.05.09, 20:33 |
Да, не раньше Разработчикам стандартной библиотеки есть время накодить и отладить даже по бумажке. |
Автор: Radagast 19.05.09, 19:21 |
какие есть реальные препятствия тому, чтобы Стандарт появился в этом году? |
Автор: mas912 21.05.09, 06:26 |
Без понятия. Но - 3 заседания комитета в год В слайдах BoostCon09 был примерный план принятия. |
Автор: Radagast 27.05.09, 21:13 |
отвечая на собственный вопрос http://www.research.att.com/~bs/C++0xFAQ.html#what-features Цитата The standard is expected to be ready for final national votes in 2009 -- hopefully yielding C++09 even if the ISO bureaucracy takes some time work through its formalities. Учитывая последнюю дату изменения - 15 мая, думаю, эта фраза всё еще актуальна...будем надеяться... Добавлено Цитата After about a year's work -- probably September 2009 -- the committee will vote out a final draft for the national standards bodies to vote on. That final draft (FDIS) is likely to become the new standard with only typographical changes a few months later. |
Автор: D_KEY 23.06.09, 06:42 |
Кто-нибудь подробно уже изучал С++'ные лямбды? Как сделать рекурсивную лямбда-функцию на новом С++? |
Автор: Flex Ferrum 23.06.09, 06:44 |
Цитата D_KEY @ Кто-нибудь подробно уже изучал С++'ные лямбды? Как сделать рекурсивную лямбда-функцию на новом С++? Видимо, об этом ты нам расскажешь. |
Автор: D_KEY 23.06.09, 06:54 |
Цитата Flex Ferrum @ Цитата D_KEY @ Кто-нибудь подробно уже изучал С++'ные лямбды? Как сделать рекурсивную лямбда-функцию на новом С++? Видимо, об этом ты нам расскажешь. Если узнаю как, расскажу |
Автор: mas912 23.06.09, 07:12 |
D_KEY Подойдёт? <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> []{[](){}();}(); |
Автор: D_KEY 23.06.09, 07:19 |
А можно объяснить? Почему после первых [] идет не список аргументов, а тело? Почему после вложенного пустого тела и "главного" тела, идут ()? |
Автор: mas912 23.06.09, 10:04 |
lambda-decl { lambda2-decl { lambda2-call} } lambda-call где decl - объявление: [] и []() call - вызов: (); Список аргументов можно не писать, если он пуст; скобки идут для вызова, то есть, в теле лямбды1 идёт объявление и вызов лямбды2, после чего идёт вызов лямбды1. |
Автор: D_KEY 23.06.09, 10:13 |
Цитата mas912 @ lambda-decl { lambda2-decl { lambda2-call} } lambda-call где decl - объявление: [] и []() call - вызов: (); Список аргументов можно не писать, если он пуст; скобки идут для вызова, то есть, в теле лямбды1 идёт объявление и вызов лямбды2, после чего идёт вызов лямбды1. Спасибо! Кажется понял... Хотя, я не понимаю, где тут рекурсия... Как вызвать в теле лямбды эту же лямбда-функцию? Как будет выглядеть, например, рекурсивное вычисление факториала с помощью лямбда? Вот обычная функция: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> int f( int n ) { return n < 2 ? 1 : n * f(n-1); } |
Автор: MT-Wizard 23.06.09, 11:11 |
А вот лямбда: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> std::function<unsigned(unsigned)> f = [&f](const unsigned n) { return n < 2 ? 1 : n * f(n - 1); }; |
Автор: D_KEY 23.06.09, 11:22 |
Цитата MT-Wizard @ А вот лямбда: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> std::function<unsigned(unsigned)> f = [&f](const unsigned n) { return n < 2 ? 1 : n * f(n - 1); }; Такой вариант приходит в голову, но не нет ли здесь неопределенного поведения, ведь f - неинициализированный объект на момент передачи в лямбда-функцию? |
Автор: MT-Wizard 23.06.09, 12:06 |
А в чём принципиальное отличие от <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> ?std::function<unsigned(unsigned)> f; f = [&f](const unsigned n) { return n < 2 ? 1 : n * f(n - 1); }; Ведь внутри будет использовано значение f на момент вызова лямбды. |
Автор: D_KEY 23.06.09, 12:09 |
Цитата MT-Wizard @ А в чём принципиальное отличие от <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> ?std::function<unsigned(unsigned)> f; f = [&f](const unsigned n) { return n < 2 ? 1 : n * f(n - 1); }; Ведь внутри будет использовано значение f на момент вызова лямбды. Скорее всего, действительно верно. Спасибо! Жаль, что нельзя сделать рекурсию без введения дополнительных сущностей... |
Автор: MT-Wizard 23.06.09, 12:29 |
Не придумали аналога this для лямбды |
Автор: mas912 23.06.09, 13:41 |
D_KEY Инициализированный. Присваивание лямбды в функцию будет в рантайме, вызов тоже (и вызов функции из лямбды). |
Автор: Большой 24.06.09, 12:53 |
Цитата Flex Ferrum @ Любителям TDM-сборок MinGW придется немножко подождать... Сколько - не известно... ура появились |
Автор: Flex Ferrum 24.06.09, 12:55 |
Ага. Достаточно давно уже. Я тут еще из их репозитория выкачал бранч с поддержкой лямбд - тоже весьма зачетно. Хотя при сборке (под виндой) без бубна не обошлось. |
Автор: pan2004 24.06.09, 17:58 |
Цитата Flex Ferrum @ Я тут еще из их репозитория выкачал бранч с поддержкой лямбд - тоже весьма зачетно И насколько они там развиты? К gcc 4.5 включить их в основную ветку могут? |
Автор: Flex Ferrum 24.06.09, 18:22 |
Ну, простые случаи работает. А вглубь не копал. |
Автор: Flex Ferrum 19.07.09, 17:29 |
Итак, на последней встрече во Франкфурте комитет проголосовал за то, чтобы Concepts были исключены из текущего драфта стандарта: Цитата On Monday, July 13th 2009 Concepts were dramatically voted out of C++0x during the C++ standards committee meeting in Frankfurt. This shocking news raises many questions and concerns. Unquestionably, these will be discussed in various forums in coming weeks and months. However, I will try to answer three burning questions here: What led to the failure of Concepts? How will the removal of Concepts affect C++0x? Will Concepts make a comeback in the near future? http://www.informit.com/guides/content.asp...plus&seqNum=441 Комментарий из списка рассылки comp.std.c++: Цитата The Committee voted to remove concepts from the version of the standard now being worked on because we estimated it would take at least 2 more years, and possibly 5, to complete the work and publish. With many other desirable features ready to go, and with the current standard already more than 10 years old, that seemed too long a delay. The choice was difficult, and nobody was happy about having to drop concepts, but the alternatives -- 5 years delay or standardizing an unusable version of concepts -- were far worse. Removing concepts will take some time, so the publication date of the new standard might slip by 3 months or so, due specifically to the removal of concepts. As Beman noted in an earlier message, we had to lengthen our schedule still more for other reasons. The Committee still wants concepts in C++, and will continue developing it in anticipation of the next update of the standard. The Removal of Concepts From C++0x Так что в принципе, не все так плохо. Если кто-то кинет ссылку на полный review их франкфуртской встречи - будет просто супер! |
Автор: miksayer 19.07.09, 20:35 |
а что это такое? киньте, пожалуйста, ссылку, где можно почитать |
Автор: DEADHUNT 19.07.09, 20:51 |
www.open-std.org |
Автор: DEADHUNT 22.07.09, 13:07 |
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> class T { public: void foo() const && { } }; в данном методе this будет иметь тип const T &&this? а то в 9.3.2 ничего не написано про ref-qualifier. |
Автор: Masterkent 22.07.09, 16:23 |
Цитата DEADHUNT @ <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> class T { public: void foo() const && { } }; в данном методе this будет иметь тип const T &&this? В данном методе выражение this (если его туда поместить) - это rvalue типа T const *. Раз не написано, значит, на тип this он никак не влияет. |
Автор: DEADHUNT 22.07.09, 16:57 |
как это не влиет, если ref-qualifier предназначен для non-static class member. |
Автор: Masterkent 22.07.09, 19:19 |
А зачем ему влиять на тип this? Он предназначен для различения lvalue и rvalue, передаваемых в качестве implied object argument, - по аналогии с обычными аргументами функции: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct X { static void f(X const &); static void f(X &&); void g() const &; // type of implicit object parameter is X const & void g() &&; // type of implicit object parameter is X && }; void h() { X x; X::f(x); // calls f(X const &) X::f(X()); // calls f(X &&) x.g(); // calls g() const & X().g(); // calls g() && } this тут не при делах вообще. |
Автор: DEADHUNT 22.07.09, 19:44 |
спасибо за примеры, буду разбираться. |
Автор: Hryak 24.07.09, 19:08 |
А, вот ты про что... Дык, что касается ругательств только GCC - сам же привёл про "no diagnostic is required", чего ты от компиляторов хочешь... А к (1) приведенные тобой цитаты не подошьёшь, т.к. имя i в аргументе по умолчанию однозначно ссылается на член класса (см выше про "an unqualified name that occurs, for instance, in a type or default argument expression in the parameter-declaration-clause") |
Автор: DEADHUNT 24.07.09, 19:26 |
как же нет, при первом просмотре ссылка идёт на ::i, а имея complete scope уже на X::i, и как раз получается 2) пункт. то есть error это слишком строго, лучше warning а какого уровня(1-4)? |
Автор: Hryak 24.07.09, 19:32 |
Цитата DEADHUNT @ при первом просмотре ссылка идёт на ::i, а имея complete scope уже на X::i, и как раз получается 2) пункт. Нет там никаких первых и вторых просмотров для аргумента по умолчанию, просто "shall be a member of class X or be a member of a base class of X". Это для использования в определении класса "before its use in class X". Да не слишком строго, "the program"-то "is ill-formed"... |
Автор: Большой 31.07.09, 09:11 |
Доступен GCC 4.4.1 Похоже лямбд и в GCC 4.5 небудет |
Автор: Flex Ferrum 31.07.09, 09:13 |
Скачай себе бранч, и пользуйся. Только его сначала сбилдить надо. По поводу мерджа в лямбд в транк - я так понял, что человек, который решил реализовать лямбды в gcc, забил на это в конце прошлого года (судя по истории изменений). Подхватит ли кто его флаг? Вот вопрос. |
Автор: DEADHUNT 31.07.09, 09:32 |
Цитата Flex Ferrum @ Скачай себе бранч, и пользуйся. Только его сначала сбилдить надо. По поводу мерджа в лямбд в транк - я так понял, что человек, который решил реализовать лямбды в gcc, забил на это в конце прошлого года (судя по истории изменений). Подхватит ли кто его флаг? Вот вопрос. всеволишь объект создать с оператором (), как я понял вроде ничего сложного. |
Автор: Flex Ferrum 31.07.09, 09:39 |
Я так понял, что есть там свои тонкости. Глубоко не вникал, но с capture-списком нужно повозиться. |
Автор: Большой 31.07.09, 15:32 |
непонял ты к чему. Добавлено Flex Ferrum Скачай себе бранч, и пользуйся что это и где взять? |
Автор: DEADHUNT 31.07.09, 15:48 |
если не знаешь что это такое, то тебе лучше не брать но на всякий случай http://gcc.gnu.org/svn/gcc/branches/cxx0x-lambdas-branch/ |
Автор: Большой 31.07.09, 16:30 |
Очень хорошая шутка Добавлено Flex Ferrum я так и не понял,они чё совсем лямбды делать не будут? |
Автор: DEADHUNT 31.07.09, 16:46 |
http://gcc.gnu.org/gcc-4.5/cxx0x_status.html пока наверное нет, а зачем так понадобились lambda-expressions? |
Автор: Большой 31.07.09, 16:49 |
DEADHUNT Надоело функторы писать состоящие из 2-3 строк кода. |
Автор: Flex Ferrum 31.07.09, 17:25 |
А я почем знаю? Я за их мейл-листом не слежу. Качаешь исходники из их репозитория (ветку с лямбдами), выкчиваешь еще пару библиотек (для работы с длинными целыми и еще какую-то), компилируешь с помощью текущей версии gcc (компиляет достаточно быстро), делаешь make install, и пользуешься. А, да. К MinGW нужно msys выкачать (без него не сделаешь autoconf/automake). |
Автор: Flex Ferrum 02.08.09, 17:47 |
Цитата Flex Ferrum @ Качаешь исходники из их репозитория (ветку с лямбдами), выкчиваешь еще пару библиотек (для работы с длинными целыми и еще какую-то), компилируешь с помощью текущей версии gcc (компиляет достаточно быстро), делаешь make install, и пользуешься. А, да. К MinGW нужно msys выкачать (без него не сделаешь autoconf/automake). Не, на самом деле - это я погорячился. gcc 4.5 (основной транк) собрать под винду - это тот еще квест. Но, вполне проходимый... |
Автор: Большой 02.08.09, 20:30 |
Flex Ferrum да, засада. Подожду еще. (Пока еще не сильно приперло) |
Автор: Flex Ferrum 03.08.09, 07:59 |
Ну, на самом деле там не все так страшно. Просто долго времени ушло на выяснение правильной последовательности запуска make'ов. Засада в другом. Бранч (который с лямбдами) содержит как минимум одну достадную ошибку в плане обработки блока __try/__catch. Выяснил это позавчера, когда игрался с std::unordered_map. Основной транк этой ошибки не содержит, но с лямбдами его мерджить надо. |
Автор: DEADHUNT 03.08.09, 08:03 |
зачем в gcc __try/__catch? |
Автор: Flex Ferrum 03.08.09, 08:09 |
А я почем знаю? Добавлено Код, который вызывал ошибку: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // Definitions of class template _Hashtable's out-of-line member functions. template<typename _Key, typename _Value, typename _Allocator, typename _ExtractKey, typename _Equal, typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, bool __chc, bool __cit, bool __uk> typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::_Node* _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>:: _M_allocate_node(const value_type& __v) { _Node* __n = _M_node_allocator.allocate(1); __try { #ifdef _GLIBCXX_INCLUDE_AS_CXX0X _M_node_allocator.construct(__n, __v); #else _M_get_Value_allocator().construct(&__n->_M_v, __v); #endif __n->_M_next = 0; } __catch(...) { _M_node_allocator.deallocate(__n, 1); __throw_exception_again; } return __n; } |
Автор: DEADHUNT 03.08.09, 08:12 |
теперь понятно, они просто там ещё и C++ используют. |
Автор: archimed7592 03.08.09, 08:17 |
Нда... |
Автор: Flex Ferrum 03.08.09, 08:26 |
Да не, ты не понял. Это исходники STL (часть реализации unordered_map). Сам gcc - на чистом C. C++-реализация - в отдельном бранче болтается. |
Автор: DEADHUNT 03.08.09, 08:30 |
в STL конечно надо использовать обработку исключений. |
Автор: Flex Ferrum 03.08.09, 19:06 |
Кстати, шутки - шутками, а часть фронт-энда на плюсах уже переписали. Уже зашли разговоры о том, чтобы основной транк 4.5 переводить на плюсовую реализацию... Также есть немалая вероятность, что лямбды в 4.5 таки будут. |
Автор: DEADHUNT 03.08.09, 19:51 |
откуда такая вероятность? Цитата Flex Ferrum @ По поводу мерджа в лямбд в транк - я так понял, что человек, который решил реализовать лямбды в gcc, забил на это в конце прошлого года (судя по истории изменений). |
Автор: miksayer 03.08.09, 21:00 |
кстати, а что у msvc предвидится по этому вопросу? |
Автор: Flex Ferrum 04.08.09, 06:38 |
http://gcc.gnu.org/ml/gcc/2009-08/msg00038.html Добавлено Кстати, занятные идеи по поводу лямбд здесь описываются: http://gcc.gnu.org/ml/gcc/2009-08/msg00045.html Причем, судя по всему, версия в бранче их кушает... Добавлено Сам некоторое количество раз порывался написать auto в качестве аргумента лямбда-функции. Но, компиль не скушал... Добавлено Да, и ветку с лямбдами таки смёрджили. Пойду перекомпилять. |
Автор: Большой 19.08.09, 21:50 |
было бы совсем хорошо. |
Автор: mas912 21.08.09, 20:21 |
miksayer В смысле, предвидится? В MSVC уже есть, начиная с CTP они (лямбды). В ICC тоже. Flex Ferrum Просто в транке она или есть в каком-нить snapshot'e? Просто из транка боюсь собирать , неохота сырой компилятор ставить в системе. Добавлено Цитата Также есть немалая вероятность, что лямбды в 4.5 таки будут. А, лучше бы nullptr прикрутили, вкупе с constexpr (последнего жутко не хватает и никто до сих пор не сделал). |
Автор: Flex Ferrum 21.08.09, 21:47 |
Нет. Только в бранче. Снапшот (собранный) есть у меня. Попробую с Vot'ом договориться, и свой билд здесь выложить (архив, правда, в райное двухсот метров, exe-шники не strip'пил). Цитата mas912 @ А, лучше бы nullptr прикрутили, вкупе с constexpr (последнего жутко не хватает и никто до сих пор не сделал). А мне, например, raw-строковых литералов. |
Автор: mas912 22.08.09, 08:39 |
А почему в бранче? Я думал, разработку ведут в транке, "тэгя" релизы и "бранча" экспериментальные ветки + поддерживаемые релизы. По поводу raw строк, где-то видел патч, там тривиально, и странно, что его до сих пор не включили в транк. |
Автор: Flex Ferrum 28.08.09, 17:15 |
Выложил свою сборку gcc 4.5 (mingw) с лямбдами. Информация о версии: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> P:\Temp\gcc\MinGW\libexec\gcc\mingw32\4.5.0>gcc -v Using built-in specs. Target: mingw32 Configured with: ../../configure --prefix=/mingw --host=mingw32 --target=mingw32 --program-prefix= --with-as=/mingw/bin/ as.exe --with-ld=/mingw/bin/ld.exe --with-gcc --with-gnu-ld --with-gnu-as --enable-threads --disable-nls --enable-langua ges=c,c++ --disable-win32-registry --disable-shared --without-x --enable-interpreter --enable-hash-synchronization --ena ble-libstdcxx-debug --with-gmp-include=/projects/common/GMP/4.3.1 --with-gmp-lib=/projects/common/GMP/4.3.1/.libs --with -mpfr-include=/projects/common/MPFR/2.4.1 --with-mpfr-lib=/projects/common/MPFR/2.4.1/.libs : (reconfigured) ../../confi gure --prefix=/mingw --host=mingw32 --target=mingw32 --program-prefix= --with-as=/mingw/bin/as.exe --with-ld=/mingw/bin/ ld.exe --with-gcc --with-gnu-ld --with-gnu-as --enable-threads --disable-nls --disable-win32-registry --disable-shared - -without-x --enable-interpreter --enable-hash-synchronization --enable-libstdcxx-debug --with-gmp-include=/projects/comm on/GMP/4.3.1 --with-gmp-lib=/projects/common/GMP/4.3.1/.libs --with-mpfr-include=/projects/common/MPFR/2.4.1 --with-mpfr -lib=/projects/common/MPFR/2.4.1/.libs host_alias=mingw32 target_alias=mingw32 --enable-languages=c,c++ --no-create --no -recursion Thread model: win32 gcc version 4.5.0 20090803 (experimental) (GCC) Добавлено Выложил cвой стапшот as-is... За работоспособность не ручаюсь, но у меня работает. |
Автор: amdei 30.08.09, 03:26 |
А что такое "raw-строковые литералоы"? |
Автор: MyNameIsIgor 30.08.09, 05:07 |
amdei, смотри первый пост этой темы. |
Автор: Бобёр 02.09.09, 07:57 |
похоже, многие из фич Стандарта 0x будут мочить. уже начали: http://www.devx.com/cplus/Article/42448/0/ http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=441 Стандарт и так уже стал не 0x, а скорее 1x, видимо что бы не стал таки 2x, решили подсократить... |
Автор: Flex Ferrum 02.09.09, 08:49 |
Бобер, это даже не вчерашняя, это позавчерашняя новость. Пока все идет к тому, что кроме концептов из стандарта ничего выкидывать не будут. |
Автор: Бобёр 02.09.09, 08:58 |
ну, посмотрим. |
Автор: Qraizer 02.09.09, 10:37 |
А концепты жалко. Я так на них рассчитывал... |
Автор: Flex Ferrum 02.09.09, 10:44 |
Ну, видимо, не один ты. Попробуй собрать ветку концептов из репозитория gcc. Я так понял, что ее ведут как раз те же люди, которые продвигают концепты в стандарте. |
Автор: Qraizer 02.09.09, 11:02 |
А смысл, если это всего лишь расширение Стандарта получится? Руку набить разве что. Я хочу ими "документировать" и хочу избавиться от расшифровки диагностик (мой личный рекорд: одна ошибка - 1,3Мб листинг). Вон, typeof там сроду был, полезнейшая вещь иногда. И часто его можно было видеть, когда он был нужен? |
Автор: Flex Ferrum 02.09.09, 11:03 |
|
Автор: mas912 03.09.09, 10:33 |
Интересно, концепты пойдут в TR2 или TR3. |
Автор: Flex Ferrum 03.09.09, 10:37 |
Вопрос хороший. И вопрос еще лучше - а где посмотреть текущее состояние TR2? Гугл практически никаких ссылок не дает... |
Автор: mas912 03.09.09, 12:41 |
Самое последнее, что я видел, это C++ Library Working Group Status Report (Post San Francisco 2008) (N2870, там есть разделы "New Library Components Accepted into TR2", "New Library Components Planned for a Future TR", "Evolution of papers targetting future TRs". Большинство предложений там из буста (filesystem, networking (boost.asio), ranges, etc.). Но это по библиотекам, а вот что по самому языку, мне неизвестно. |
Автор: Flex Ferrum 25.09.09, 05:36 |
Yes! Цитата Re: C++0x lambdas in 4.5? * From: Jason Merrill <jason at redhat dot com> * To: Kenny Simpson <theonetruekenny at yahoo dot com> * Cc: gcc at gcc dot gnu dot org * Date: Thu, 24 Sep 2009 10:44:38 -0400 * Subject: Re: C++0x lambdas in 4.5? * References: <603843.64256.qm@web51508.mail.re2.yahoo.com> On 09/22/2009 10:16 PM, Kenny Simpson wrote: Will the lambda branch be merged into 4.5? Yes. Jason http://gcc.gnu.org/ml/gcc/2009-09/msg00507.html |
Автор: Masterkent 25.09.09, 19:51 |
Поскольку в последнее время на форуме стали много поговаривать о хаках вокруг std::basic_string, не лишним будет заметить, что в стандарте планируются важные изменения насчёт строк: 1) непрерывность расположения элементов std::basic_string будет гарантироваться, как и в случае с std::vector: Цитата N2914 - 21.4.1/3 The char-like objects in a basic_string object shall be stored contiguously. That is, for any basic_string object s, the identity &*(s.begin() + n) == &*s.begin() + n shall hold for all values of n such that 0 <= n < s.size(). Цитата 21.4.5 const_reference operator[](size_type pos) const; reference operator[](size_type pos); 1 Returns: If pos < size(), returns *(begin() + pos). Otherwise, if pos == size(), the const version returns charT(). Otherwise, the behavior is undefined. 2) Copy-on-write реализации std::basic_string не будут допускаться. Как альтернатива std::basic_string, возможно, появится rope (или что-то похожее) с применением этой идиомы. Подробности см. в N2668 Цитата 21.4.1/4 References, pointers, and iterators referring to the elements of a basic_string sequence may be invalidated by the following uses of that basic_string object: — as an argument to any standard library function taking a reference to non-const basic_string as an argument.234 — Calling non-const member functions, except operator[], at, front, back, begin, rbegin, end, and rend. Если это дело примут, то хак вроде <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> #include <cstddef> #include <iostream> #include <string> int main() { std::size_t const size = 5; std::string s(size, '\0'); std::cin.read(&s[0], size); // undefined behavior in C++03, well-defined in C++0x std::cout << s << std::endl; } перестанет быть хаком. |
Автор: archimed7592 25.09.09, 19:58 |
Хммм... А из каких именно соображений, случаем, не знаешь? |
Автор: Masterkent 25.09.09, 20:00 |
В основном это связано с конкурентным доступом. По ссылке всё объяснено. Правда, я пока так и не понял смысл предлагаемого определения c_str и data. |
Автор: Masterkent 26.09.09, 15:21 |
Мда, похоже, не мне одному описание c_str и data в N2914 представляется неподходящим - см. issue 876. Вот это Цитата In 21.4.7.1 [string.accessors] replace the now common returns clause of c_str() and data() by the following three paragraphs: Returns: A pointer p such that p+i == &operator[](i) for each i in [0, size()]. Throws: Nothing. Complexity: Constant time. уже как-то получше будет |
Автор: Flex Ferrum 06.10.09, 18:06 |
Да. lambda branch действительно смерджили с основным транком gcc. Помимо лямбд там появятся: - Explicit conversion operators - Standard Layout Types - Local and unnamed types as template arguments Добавлено Последняя фишка весьма забавная, надо отметить. |
Автор: Большой 08.10.09, 05:24 |
Цитата archimed7592 @ T t; // lvalue T &rt = t; // lvalue reference T &&rrt = t; // rvalue reference Я что-то не пойму ссылка на ссылку объявляется так как в примере выше? Я просто думал, что так <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> T t; T &rt = t; T &&rrt = rt; |
Автор: Flex Ferrum 08.10.09, 05:46 |
Да. Добавлено Вопрос к Masterkent'у. Masterkent, не известно ли тебе - по какой причине в новой версии стандарта всё еще запрещено объявлять шаблонные члены в локальных классах? Просто забавно получается - в качестве шаблонных параметров их разрешили использовать, а шаблонизировать сами эти классы - нет. Иначе как было бы здорово (на мой взгляд) объявлять полиморфные функторы: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // Некий обобщенный код: template<typename T1, typename T2, typename F> void generic_foo(T1 a, T2 b, F fn) { // ... fn(a, b); // ... } void foo(int a, double b) {} void foo(std::string a, char b) {} void bar() { class FTor { template<typename T1, typename T2> void operator()(T1 a, T2 b) {foo(a, b);} } ftor; generic_foo(10, 103.2, ftor); generic_foo(std::string("abeagew"), 'a', ftor); } Но... Так нельзя... |
Автор: archimed7592 08.10.09, 09:10 |
Это не ссылка на ссылку. Это rvalue ссылка (в отличии от lvalue ссылки). Разница между ними настолько же существенная, как и между указателем и ссылкой. |
Автор: Большой 08.10.09, 11:15 |
archimed7592т.е. ты хочешь сказать, что это не ссылка на ссылку, а правильнее говорить ссылка на rvalue? или опять я туплю |
Автор: Flex Ferrum 08.10.09, 11:18 |
Цитата Большой @ archimed7592т.е. ты хочешь сказать, что это не ссылка на ссылку, а правильнее говорить ссылка на rvalue? Да. |
Автор: archimed7592 08.10.09, 12:25 |
Цитата Большой @ archimed7592т.е. ты хочешь сказать, что это не ссылка на ссылку, а правильнее говорить ссылка на rvalue? или опять я туплю 1. Это не ссылка на ссылку. 2. Это называется rvalue reference, а как правильнее обзывать - решай сам. 3. Базовую информацию о том, что такое rvalue reference и чем она отличается от lvalue reference ты можешь получить в первом посте. 4. Зная что представляет из себя ссылка по определениям C++03 (а это определение сильно не изменилось в С++09), ты бы понимал, что ссылка на ссылку - это некая абстрактная сущность (которой к слову в С++09 не появилось), которая не имеет абсолютно никакого смысла. Объясню про п. 4 чуть подробнее. Есть такое понятие как указатель на указатель на T. Смысл этой сущности состоит в том, что с её помощью можно изменять значение некоторого объекта ссылающегося на объект типа T, т.е. модифицировать указатель. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> int x, y; int *pi = &x, **ppi = π x = 10; y = 20; std::cout << *pi << std::endl; // 10; x += 5; std::cout << *pi << std::endl; // 15; *ppi = &y; std::cout << *pi << std::endl; // 20; y += 5; std::cout << *pi << std::endl; // 25; Что же касается ссылки - связь с объектом на который она указывает ссылка получает во время инициализации и изменить эту связь таким образом, чтобы ссылка ссылалась на другой объект в принципе невозможно (формально, да, можно подменить объект в памяти другим при помощи new (ptr) T(), но изменением связи это назвать сложно). Тот факт что технически ссылка может представлять из себя объект, указывающий на другой объект, т.е. указатель никаким образом не помогает нам изменить связь ссылки с объектом, если так будет проще: в С++ не предусмотрено для этих целей синтаксиса; ни в С++03, ни в С++09. Для более лёгко понимания того, что из себя представляет ссылка в некоторой литературе советуют воспринимать ссылку как синоним имени объекта для доступа к нему. Как ты сам понимаешь синоним на синоним всё равно будет представлять из себя синоним. |
Автор: Masterkent 08.10.09, 14:35 |
Цитата Flex Ferrum @ Masterkent, не известно ли тебе - по какой причине в новой версии стандарта всё еще запрещено объявлять шаблонные члены в локальных классах? Не знаю. IMHO, скорее всего, такое в принципе возможно формализовать (без получения негативных побочных эффектов), но комитет просто не видит в этом достаточной выгоды, чтобы переписывать правила. |
Автор: pan2004 08.10.09, 15:36 |
Цитата Flex Ferrum @ Да. lambda branch действительно смерджили с основным транком gcc. Помимо лямбд там появятся: - Explicit conversion operators - Standard Layout Types - Local and unnamed types as template arguments Насчет последнего - local понятно, но unnamed это как? Чтото вроде этого: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <class T> class A {...}; void foo() { A<struct {int a; int b;}> obj; } ? ПС Еще обещают в gcc 4.5 повысить скорость компиляции шаблоного кода и добавить Link-time оптимизацию. Так глядишь и студийный компилятор по скорости догонит... |
Автор: Flex Ferrum 08.10.09, 16:52 |
Цитата pan2004 @ ПС Еще обещают в gcc 4.5 повысить скорость компиляции шаблоного кода и добавить Link-time оптимизацию. Уже. |
Автор: Masterkent 08.10.09, 18:11 |
Класс или перечисление получается безымянным, когда в его определении непосредственно после ключевого слова class, struct, union или enum отсутствует имя. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct NamedClass {}; enum NamedEnumeration { enumerator_of_named_enumeration_type }; typedef struct : NamedClass {} UnnamedClass; // has name for linkage purposes only enum { enumerator_of_unnamed_enumeration_type }; template <class T> void f(T) {} int main() { f(NamedClass()); // well-formed in C++03 and C++0x f(enumerator_of_named_enumeration_type); // well-formed in C++03 and C++0x f(UnnamedClass()); // ill-formed in C++03, well-formed in C++0x f(enumerator_of_unnamed_enumeration_type); // ill-formed in C++03, well-formed in C++0x } Цитата pan2004 @ Чтото вроде этого: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <class T> class A {...}; void foo() { A<struct {int a; int b;}> obj; } ? Так делать нельзя: Цитата N2914 - 14.3/1 template-argument:
constant-expression
type-id
id-expression Цитата N2914 - 8.1/1 type-id:
type-specifier-seq attribute-specifieropt abstract-declaratoropt Цитата N2914 - 7.1.6/3 A type-specifier-seq shall not define a class or enumeration unless it appears in the type-id of an alias-declaration |
Автор: Flex Ferrum 08.10.09, 18:15 |
Цитата Masterkent @ Класс или перечисление получается безымянным, когда в его определении непосредственно после ключевого слова class, struct, union или enum отсутствует имя. Можешь привести пример (пусть и синтетический) но более-менее реального применения этой фишки? |
Автор: Masterkent 08.10.09, 18:20 |
Цитата Flex Ferrum @ Можешь привести пример (пусть и синтетический) но более-менее реального применения этой фишки? Перечислениям довольно часто не дают имени, ну а безымянные классы лично мне не пригождались - за исключением анонимных union-ов, но ими шаблоны по-любому не инстанцируешь. |
Автор: Flex Ferrum 08.10.09, 18:22 |
Цитата Masterkent @ Перечислениям очень часто не дают имени, ну а безымянные классы лично мне не пригождались. Ну, вообще говоря, по-моему, отсутствие имени у таких перечислений не мешало мне использовать их в качестве параметров шаблонов... У них ведь, вроде как (у констант, в смысле) получается тип int. Или я чего-то недопонимаю? |
Автор: Masterkent 08.10.09, 18:36 |
Цитата Flex Ferrum @ отсутствие имени у таких перечислений не мешало мне использовать их в качестве параметров шаблонов VC++ позволяет инстанцировать шаблоны безымянными типами. Цитата C++03 - 7.2/4 Each enumeration defines a type that is different from all other types. Following the closing brace of an enum-specifier, each enumerator has the type of its enumeration. |
Автор: Flex Ferrum 08.10.09, 18:56 |
Цитата Masterkent @ но комитет просто не видит в этом достаточной выгоды, чтобы переписывать правила. Странно (на мой взгляд). Достаточно взглянуть на приведенный пример. Ведь это просто следующий шаг (после лямбд и инстанцирования локальными типами). in-place-полиморфные врапперы, избавляющие кодера от, гм..., ненужных шаманств. Другой пример (по идее, должен компилироваться): <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> class Foo { public: typedef boost::variant<int, std::string, double> var_type; void Process(var_type const& v) { struct Processor : boost::static_visitor<> { Foo* m_Object; Processor(Foo* obj) : m_Object(obj) {;} template<typename T> void operator()(T val) const {m_Object->Process(val);} } p(this); boost::apply_visitor(p, v); } private: void Process(int a); void Process(std::string a); void Process(double a); }; Теперь прикинь, сколько тебе придется писать сейчас. А учитывая, что этот Processor можно завернуть в макрос: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> #define DEF_VISITOR(cls, method) \ struct Processor : boost::static_visitor<> \ { \ cls* m_Object; \ Processor(cls* obj) : m_Object(obj) {;} \ template<typename T> void operator()(T val) const {m_Object->Method(val);} \ } с последующим использованием: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> class Foo { public: typedef boost::variant<int, std::string, double> var_type; void Process(var_type const& v) { DEF_VISTOR(Foo, Process) p(this); boost::apply_visitor(p, v); } private: void Process(int a); void Process(std::string a); void Process(double a); }; разница становится еще более очевидной. Добавлено Только что проверил (на полусобранном gcc 4.5) - локальный класс в теле метода класса имет полный доступ к private-потрохам класса. Что и требуется. |
Автор: Qraizer 08.10.09, 19:56 |
Цитата Flex Ferrum @ Ну, значениями тебе никто не запрещал пользоваться, перечисления-то не требуют квалификации именем своего типа, т.к. они не создают областей видимости. Но ведь речь-то шла не о значениях, а о типе. Значение параметром в typename T не передашь.Ну, вообще говоря, по-моему, отсутствие имени у таких перечислений не мешало мне использовать их в качестве параметров шаблонов... У них ведь, вроде как (у констант, в смысле) получается тип int. Или я чего-то недопонимаю? Проблема стала актуальной с появлением decltype и наделением auto новых возможностей. Их-то не запрещается использовать с безымянными типами. |
Автор: Большой 09.10.09, 06:29 |
Flex Ferrum когда gcc 4.5 обещают? |
Автор: Flex Ferrum 09.10.09, 06:34 |
Я ожидаю не раньше марта следующего года (судя по датам выходов предыдущих релизов). Сейчас четвертый день пытаюсь его из исходников под MinGW сбилдить... Вообщем, как только получится - выложу здесь. |
Автор: Большой 09.10.09, 09:06 |
было бы очень хорошо |
Автор: Masterkent 09.10.09, 10:42 |
Можно сделать Processor закрытым членом Foo. Тут, кстати, видна другая проблема: шаблонными аргументами нельзя передавать имена функций. Довольно неприятное ограничение. Указатели на функции-члены неудобны: ни с перегруженными функциями, ни с шаблонами функций, ни с функциями, имеющими аргументы по умолчанию, их зачастую нормально не поюзаешь. Иметь дело с именами функций было бы куда удобнее: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // подобное использование virtual, .(Fn) и .. - это просто мои допущения, в C++0x ничего такого нет. template <virtual Fn, class C> class MemFnBinder { public: MemFnBinder(C const &x) : m_obj(x) {} template <class... Args> auto operator ()(Args &&... args) const -> decltype(m_obj.(Fn)(args...)) { return m_obj.(Fn)(args...); } private: C m_obj; }; template <virtual Fn, class C> MemFnBinder<Fn, C> bind(C const &x) { return MemFnBinder<Fn, C>(x); } struct X { void func(int, int = 0); }; void f() { std::function<void (int)> fn1 = bind<..func>(X()); std::function<void (int, int)> fn2 = bind<..func>(X()); } И, в частности, твой макрос можно было бы переписать примерно так: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <class C, virtual Fn> class Processor : boost::static_visitor<> { public: Processor(C* obj) : m_object(obj) {} template <class T> void operator()(T val) const { m_object->(Fn)(val); } private: C* m_object; } причём, по-моему, не было бы никакого смысла делать такой шаблон локальным. Если он настолько обобщённый, что используется сразу в нескольких местах, то, наверное, ему самое место в пространстве имён. Локальным имело бы смысл делать код, который нигде больше, кроме как в данной функции, не используется - например: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> template <class BidirectionalIterator> void reverse(BidirectionalIterator first, BidirectionalIterator last) { struct Aux { template <class BidirIt> void operator()(BidirIt first, BidirIt last, std::bidirectional_iterator_tag) { for (; first != last && first != --last; ++first) (swap)(*first, *last); } template <class RanIt> void operator ()(RanIt first, RanIt last, std::random_access_iterator_tag) { for (; first < last; ++first) (swap)(*first, *--last); } }; Aux()(first, last, typename std::iterator_traits<BidirectionalIterator>::iterator_category()); } |
Автор: Flex Ferrum 09.10.09, 10:51 |
В таком случае - да. Но... Можно. Но это значит вносить изменения в интерфейс класса, что (в ряде случаев, да и вообще) некомильфо. А локальный класс (в данном случае) никуда, кроме функции (в которой объявлен) не "выглядывает". Цитата Masterkent @ Тут, кстати, видна другая проблема: шаблонными аргументами нельзя передавать имена функций. Довольно неприятное ограничение. Угумс. Именно эту проблему и есть желание обойти. Указанным мною образом. |
Автор: Masterkent 09.10.09, 11:17 |
Публичного интерфейса класса это почти не касается, поэтому проблема второсортная, IMHO. |
Автор: Flex Ferrum 09.10.09, 11:26 |
Цитата Masterkent @ Публичного интерфейса класса это почти не касается, поэтому проблема второсортная, IMHO. Зато приведет к перекомпиляции зависимого от интерфейса кода. А это уже хуже. |
Автор: Masterkent 09.10.09, 11:35 |
Если эта проблема критична, то можно поместить данный вспомогательный класс в unnamed namespace. |
Автор: Flex Ferrum 09.10.09, 11:36 |
Цитата Masterkent @ Если эта проблема критична, то можно поместить данный вспомогательный класс в unnamed namespace. Да много чего можно то. |
Автор: Masterkent 09.10.09, 11:43 |
О том и речь: есть масса неплохих workaround-ов, так что оснований для пересмотра правил здесь может быть недостаточно. |
Автор: Flex Ferrum 09.10.09, 11:48 |
Цитата Masterkent @ есть масса неплохих workaround-ов, так что оснований для пересмотра правил здесь может быть недостаточно. Но удочку закинуть все равно можно. |
Автор: Flex Ferrum 09.10.09, 12:03 |
В смысле, поинтересоваться мнением общественности по этому поводу где-нибудь в comp.std.c++ |
Автор: olias 12.10.09, 11:48 |
Цитата mas912 @ Самое последнее, что я видел, это C++ Library Working Group Status Report (Post San Francisco 2008) (N2870 This project was cancelled by SC22 in September 2008 - на главной странице комитета. Весь TR2 отменили, кроме decimal floating point arithmetic. |
Автор: Большой 13.10.09, 11:32 |
Я так понимаю из буста в новый стандарт перекочует shared_ptr. Но интересно в каком пространстве имен он будет? И в чем его основные отличия от unique_ptr? |
Автор: archimed7592 13.10.09, 11:46 |
std unique_ptr - это эволюция auto_ptr и к shared_ptr он практически никак не относится. |
Автор: Бобёр 13.10.09, 11:47 |
т.е. они фактически дали auto_ptr-у правильное название? интересно, а до алгоритмов типа remove_if у них руки дойдут? |
Автор: archimed7592 13.10.09, 11:48 |
Не совсем. Там решён ряд синтаксически-семантических проблем. |
Автор: Большой 13.10.09, 12:05 |
так подожди у них проблема вроде была с copy_if Цитата archimed7592 @ unique_ptr - это эволюция auto_ptr и к shared_ptr он практически никак не относится. Это я знаю они семантику перемещения на семантику копирования переладили, но от шареда чем отличаются? |
Автор: Flex Ferrum 13.10.09, 12:16 |
Тем, что не shared. |
Автор: archimed7592 13.10.09, 12:24 |
Цитата Большой @ Это я знаю они семантику перемещения на семантику копирования переладили, но от шареда чем отличаются? Ты это не знаешь. Во-первых, наоборот, семантику перемещения добавили, а не заменили, но её добавили по всей стандартной библиотеке, так что я не её имел ввиду. Во-вторых, как я уже сказал, к shared_ptr он практически никак не относится. Проще было бы рассказать что такое shared_ptr и что такое unique_ptr, чем перечислять их отличия. Информацию и о том и о другом можно найти в документации Boost'а. |
Автор: Flex Ferrum 13.10.09, 12:33 |
По поводу unique_ptr'а ты там ничего не найдешь, ЕМНИП. unique_ptr в бусте есть только в interprocess, и выковырять его оттуда (безболезненно) практически анрил. |
Автор: archimed7592 13.10.09, 12:57 |
Если честно, я точно не помню где я про unique_ptr proposal читал... |
Автор: miksayer 13.10.09, 15:12 |
а что там за проблемы были? |
Автор: archimed7592 13.10.09, 15:30 |
Имя не совсем соответствует действительности . В реальности remove ничего не удаляет. |
Автор: Большой 14.10.09, 06:13 |
да и в драфте есть, только лень читать было думал может кто так скажет |
Автор: olias 14.10.09, 06:44 |
Хех. unique_ptr - пере/до-работанный auto_ptr, который deprecated, вместе со stringstream. В двух словах - у unique_ptr семантика перемещения (объектом владеет только один умный указатель), а shared_ptr имеет семантику разделения (один объект могут иметь/разделять много умных указателей). Из доработов первого: - семантика перемещения (rvalue-references) - deleter'ы (функции/функторы, отвечающие за удаление объекта: в комплекте идут delete и delete[], можно задавать собственные) - поддержка конвертируемых типов с корректным удалением: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> struct A{}; struct B: A{}; std::unique_ptr<A> p(new B()); // или вообще, unique_ptr<void>. p.reset(); // delete pB По shared_ptr читайте в TR1/Boost. |
Автор: Radagast 14.10.09, 06:57 |
а зачем нужно было депрекейтить stringstream? оО |
Автор: Flex Ferrum 14.10.09, 06:58 |
Он давным давно такой, просто до сих пор не "отсохнет". |
Автор: Крон 14.10.09, 07:02 |
А что за место него рекомендуют? |
Автор: Flex Ferrum 14.10.09, 07:06 |
std::strstream. Но он (этот strstream) не умеет записывать в заранее выделенный буфер памяти. По этому stringstream до сих пор жив. |
Автор: archimed7592 14.10.09, 07:22 |
Ребят, вы ничего не путаете? Не знаю как с этим дела обстоят в С++09, но в С++03 как раз strstream был deprecated а stringstream во всю рекомендуемым и используемым. |
Автор: Flex Ferrum 14.10.09, 07:23 |
Возможно путаем. Слишком похоже называются. |
Автор: archimed7592 14.10.09, 07:25 |
Лень лезть в стандарт которого под рукой нет, но в MSDN именно strstream обзывают deprecated. |
Автор: Flex Ferrum 14.10.09, 07:25 |
Кстати, в новом стандарте упоминания о strstream есть только в приложении D (compatibility features). |
Автор: Qraizer 14.10.09, 08:02 |
Тоже лень-матушка одолела, но таки скажу, что strstream хоть никуда и не денется из соображений обратной совместимости, но и развиваться не будет (отсутствие wstrstream и вообще его шаблонности тому подтверждение), а stringstream-у не помешало бы опциональное совмещение владения буфера между собой и юзер-кодом. |
Автор: Flex Ferrum 14.10.09, 08:03 |
Цитата Qraizer @ а stringstream-у не помешало бы опциональное совмещение владения буфера между собой и юзер-кодом Угумс. Что подняло бы его применимость на порядок. |
Автор: olias 14.10.09, 11:25 |
Radagast Ну, вместо него <sstream>, там получше сделано и универсальнее. |
Автор: olias 22.10.09, 22:56 |
Прошёл слух, что в gcc 4.5 добавили constexpr. Кто-то может подтвердить? |
Автор: Flex Ferrum 23.10.09, 05:39 |
В их табличке здесь и здесь ничего такого нет. Добавлено Судя по тестом, сия фишка находится в процессе добавления. Сама конструкция constexpr распознаётся, но, например, в параметрах шаблона вызов такой функции использовать нельзя. Хотя в качестве указания размерности массива - можно. |
Автор: Flex Ferrum 23.10.09, 06:55 |
Т. е. (судя по еще некоторым тестам), сами constexpr-функции, переменные и типы описывать можно, а вот в включение их в обработку конструкции constant expression еще не сделали. |
Автор: Большой 23.10.09, 07:29 |
archimed7592 Конкретно что нас ждёт именно по шаблонам в новом стандарте. |
Автор: archimed7592 23.10.09, 08:43 |
Большой, конкретно Вам рекомендую поискать глазами слова "шаблон" и/или "template" в достаточно крупных подзаголовках в первом посте. |
Автор: olias 23.10.09, 09:13 |
Flex Ferrum Ага, спасибо. |
Автор: Flex Ferrum 23.10.09, 09:18 |
Можешь и сам потестировать. Взять gcc 4.5 (под винду) можешь здесь. |
Автор: miksayer 23.10.09, 11:34 |
что такое constant expression? просветите, пожалуйста |
Автор: archimed7592 23.10.09, 11:37 |
Цитата archimed7592 @ 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 |
Автор: olias 23.10.09, 20:14 |
А кто-то может пояснить New wording for C++0x lambdas (N2927)? В чём там отличие с предыдущей реализацией? |
Автор: Masterkent 24.10.09, 07:13 |
Решён ряд проблем, описанных в defect report-ах под номерами, перечисленными в секции "Resolved issues". Изменений в тексте черновика много, и описывать их долго. |
Автор: olias 24.10.09, 07:44 |
А, ну меня больше интересовало, нет ли там breaking changes, как в случае с rvalue references. |
Автор: Большой 15.12.09, 06:58 |
Кто сможет пояснить назаначение новых ключевых слов axiom late_check |
Автор: Flex Ferrum 15.12.09, 07:02 |
Это из концептов. Можешь расслабиться - их не будет в новом стандарте. |
Автор: Большой 15.12.09, 08:53 |
Flex Ferrum gcc сейчас поддерживает <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> initializer_list а где можно скачать последний драфт стандарта, а то похоже мой совсем устраел |
Автор: Flex Ferrum 15.12.09, 09:06 |
Да. здесь. |
Автор: olias 15.12.09, 09:38 |
А constexpr ещё нет? |
Автор: Большой 15.12.09, 10:12 |
Cool Спасибо Мой на 60 страниц тяжелее |
Автор: Flex Ferrum 15.12.09, 10:19 |
Не проверял. Судя по логам - нет. |
Автор: miksayer 15.12.09, 16:35 |
это чтобы можно было перегружать оператор = для такого случая: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> SomeClass a = {1, 2, 3} ? |
Автор: olias 15.12.09, 20:58 |
Да. В бусте эту идею эмулировали, в Boost.Assign. |
Автор: D_KEY 15.12.09, 21:53 |
Ну все-таки это вещи очень разные. |
Автор: Masterkent 15.12.09, 23:37 |
Цитата miksayer @ это чтобы можно было перегружать оператор = для такого случая: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> SomeClass a = {1, 2, 3} ? Тут нет присваивания. |
Автор: miksayer 16.12.09, 16:41 |
в каком смысле? а что тогда? Добавлено а каким примерно образом эмулировали? а то я не очень себе представляю, как это возможно |
Автор: Flex Ferrum 16.12.09, 18:18 |
Вызов конструктора. |
Автор: olias 16.12.09, 19:53 |
miksayer тут примеры. Не один-в-один, конечно, но похоже да и всяко удобнее, чем через промежуточный Си-массив. |
Автор: D_KEY 16.12.09, 20:03 |
Цитата olias @ miksayer тут примеры. Не один-в-один, конечно, но похоже да и всяко удобнее, чем через промежуточный Си-массив. А зачем это вообще нужно? Что неужели сложно сделать push_back или insert? Вот std::initializer_list другое дело. Инициализация при конструировании действительно полезна. |
Автор: olias 17.12.09, 08:36 |
D_KEY То есть, вместо "vector<int> v; v += 1,2,3,7,8,9;" предлагаешь писать <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(7); v.push_back(8); v.push_back(9); ? Понятно, что другое, но для него нужна поддержка компилятором, а она есть пока только в гцц. |
Автор: Flex Ferrum 17.12.09, 08:37 |
Для инициализации статических или глобальных контейнеров - очень даже удобно. |
Автор: D_KEY 17.12.09, 11:30 |
Цитата olias @ D_KEY То есть, вместо "vector<int> v; v += 1,2,3,7,8,9;" предлагаешь писать <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(7); v.push_back(8); v.push_back(9); ? Во-первых, совершенно не вижу смысла писать все в одну строку. Во-вторых, а что тебе не нравится? В-третьих, можно и так: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> int t[] = {1,2,3,7,8,9}; vector<int> v(t, t + sizeof(t)); Не вижу достаточных оснований менять семантику оператора. И вообще, я не понимаю, для чего было разрешать перегрузку operator,(равно как и && и ||). |
Автор: GoldFinch 17.12.09, 12:23 |
для списков, и для DSL например если надо задать список T, то можно использовать T[] но если надо задать список разных типов - то очевидно лучший вариант - перегрузка , my_array a; a+=1,"2",complex(3,4); насчет DSL - посмотри на boost.spirit, как там используется перегрузка , && || |
Автор: D_KEY 17.12.09, 12:28 |
Цитата GoldFinch @ но если надо задать список разных типов - то очевидно лучший вариант - перегрузка , my_array a; a+=1,"2",complex(3,4); А для меня очевидно, что это не стоит изменения семантики. , - это такой же "оператор", как ;. Может и это следует разрешить перегружать? Есть tuple в бусте и в новом стандарте. И ничего страшного в: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> my_array a; a += 1; a += "2"; a += complex(3,4); Я не вижу. А код гораздо читабельнее(ибо семантика не меняется). |
Автор: GoldFinch 17.12.09, 12:52 |
D_KEY, ты не видишь - другие видят; не знаешь зачем - другие знают. ; - в терминологии С++ это не оператор, читай стандарт в С++ вообще много что надо изменить и добавить |
Автор: D_KEY 17.12.09, 13:03 |
Естественно. Цитата ; - в терминологии С++ это не оператор, читай стандарт Я в курсе . Я кавычки не зря поставил. Мне не ясно почему , можно перегружать. Цитата в С++ вообще много что надо изменить и добавить |
Автор: GoldFinch 17.12.09, 13:47 |
D_KEY, не хочешь перегружать , - не перегружай, но другим-то зачем не давать? поиск "operator(\s*),(\s*)\(" в boost/ показывает что перегрузка , используется в assign, python, proto, spirit, test |
Автор: D_KEY 17.12.09, 13:58 |
Так я говорю, давай перегрузим ; или ?: Понимаешь, есть "необычные" "операторы", поведение которых строго определено и отличается от семантики вызова функции. То есть вводя перегрузку таких операторов ты меняешь их суть. В результате понять, что и в какой последовательности делает код не всегда представляется возможным. К таким "операторам" относятся, например, запятая, ||, &&, ?:. Из них запрещен только ?:. |
Автор: GoldFinch 17.12.09, 14:14 |
D_KEY, тебе знакомо понятие DSL? Если например в моем DSL || обозначает параллельные прямые - о какой последовательности речь?? |
Автор: D_KEY 17.12.09, 14:17 |
Цитата GoldFinch @ D_KEY, тебе знакомо понятие DSL? Если например в моем DSL || обозначает параллельные прямые - о какой последовательности речь?? Знакомо. Только в С++ нереально сделать нормальный DSL. "Внешний" DSL, в любом случае, лучше. |
Автор: olias 17.12.09, 14:18 |
Цитата D_KEY @ И ничего страшного в … Я не вижу. А код гораздо читабельнее(ибо семантика не меняется). Спорно. Как раз возможность использования разных сущностей в одном выражении очень удобна и читабельнее, чем написанная "в столбик", sqlite++ тому примером. Да и потоки тоже из той же серии, с ними тоже в строчку удобнее выводить, чем "cout.write("hello, "); cout.write(name);" ЗЫ а вообще, это всё оффтоп и его, наверное, надо вынести из данной темы. |
Автор: D_KEY 17.12.09, 14:21 |
Цитата olias @ Цитата D_KEY @ И ничего страшного в … Я не вижу. А код гораздо читабельнее(ибо семантика не меняется). Спорно. Как раз возможность использования разных сущностей в одном выражении очень удобна и читабельнее, чем написанная "в столбик" Во-первых, я тебе привел вариант инициализации через массив. Во-вторых, ты все правильно говоришь для случаев, когда не меняется семантика и порядок вычислений(как в этом случае). Цитата Здесь с порядком вычислений все в порядке. Он соответствует неперегруженному варианту. sqlite++ тому примером. Да и потоки тоже из той же серии, с ними тоже в строчку удобнее выводить, чем "cout.write("hello, "); cout.write(name);" |
Автор: Qraizer 17.12.09, 14:58 |
D_KEY, верно, что перегруженные operator||(), operator&&() и operator,() имеют иную семантику. Потому их и не рекомендуется перегружать. Но это не достаточно сильное обоснование для полного запрета. Тот же ?: запрещён к перегрузке по иным соображиям. |
Автор: D_KEY 17.12.09, 15:02 |
Да я и не говорю, что следует запретить. Раз есть - пусть будет. Просто непонятно, для чего нужно было такую перегрузку разрешать изначально. Цитата По каким? Тот же ?: запрещён к перегрузке по иным соображиям. |
Автор: GoldFinch 17.12.09, 15:58 |
D_KEY http://www.research.att.com/~bs/bs_faq2.html#overload-dot Цитата There is no fundamental reason to disallow overloading of ?:. I just didn't see the need to introduce the special case of overloading a ternary operator. Note that a function overloading expr1?expr2:expr3 would not be able to guarantee that only one of expr2 and expr3 was executed. Добавлено и да, действительно сложно представить зачем перегружать ?: |
Автор: D_KEY 17.12.09, 16:20 |
То есть единственной причиной по которой нельзя перегружать ?: является отсутствие смысла? Мда... А до того, что порядок вычислений меняется, никому дела нет? Не знаю. На мой взгляд, перегрузка операторов, которые не могут быть представлены, как вызов функции, противоречит как смыслу перегрузки, так и реализации этого механизма... Ладно, действительно, не в тему спор. |
Автор: Qraizer 17.12.09, 16:42 |
GoldFinch, в том-то и дело, что к трём остальным операторам это относится в той же мере. Все эти (неперегруженные) операторы вносят точку следования наравне с ;, чего не делают перегруженные, что и есть иной семантический смысл. Не знаю точно. Могу догадываться, что возникают сложности с его интерпретацией в роли метода класса. Где там this-у место? |
Автор: amk 17.12.09, 16:43 |
Тут скорее причина в другом, оператор ?: стоит несколько особняком от остальных операторов. Это скорее даже не оператор, а особая синтаксическая конструкция, вроде сокращенной записи для if…else. В том же Algol W в этом качестве можно использовать if…fi. Там в этом смысле вообще хорошо, любая конструкция является выражением, возвращающим значение. |
Автор: D_KEY 17.12.09, 17:41 |
Цитата amk @ Тут скорее причина в другом, оператор ?: стоит несколько особняком от остальных операторов. Также, как и ||, && и, тем более, запятая. Цитата Ну не совсем. Это именно выражение, в отличие от. Это скорее даже не оператор, а особая синтаксическая конструкция, вроде сокращенной записи для if…else. |
Автор: amk 17.12.09, 23:33 |
Просто для ||, && и , нет такого устойчивого стереотипа, что они означают (по крайней мере у разработчиков стандартов такой стереотип видимо есть). Плюс можно их перегрузить чтобы они были более-менее понятны. Хотя на мой взгляд лучше для первых двух операторов просто задать преобразователь в bool (вроде стандартный ), а для запятой, во избежание ненужных сюрпризов, пользоваться встроенным оператором. |
Автор: D_KEY 17.12.09, 23:38 |
Дело не только в значении, дело в поведении и порядке вычислений. Так, например, встроенный || не вычисляет второй аргумент, если первый - true, кроме того, первый аргумент всегда вычисляется до второго. А если мы перегружаем ||, то вычислены будут оба аргумента, причем в неизвестном порядке. |
Автор: amk 18.12.09, 01:35 |
Да, это проблема. Если бы можно было отложить вычисление параметров до того момента, когда они действительно понадобятся. Но в C++ такой возможности нет - это не Алгол. |
Автор: GoldFinch 18.12.09, 06:20 |
Цитата amk @ Если бы можно было отложить вычисление параметров до того момента, когда они действительно понадобятся. ленивые вычисления вполне реализуемы, правда вместо foo(x) будет чтото вроде bind(foo,x) |
Автор: D_KEY 18.12.09, 06:31 |
Цитата amk @ Да, это проблема. Если бы можно было отложить вычисление параметров до того момента, когда они действительно понадобятся. Но в C++ такой возможности нет - это не Алгол. Так вот и незачем перегружать операторы, которые семантически нельзя представить в виде функций. |
Автор: Qraizer 18.12.09, 17:10 |
D_KEY, нельзя заставлять поступать так-то и так-то исключительно из религиозных соображений. Тогда уж надо запретить перегружать + как умножение, префиксный ++ как постфиксный итп. Это было бы полезнее. Формальных же препятствий к перегрузке этих операций нет. |
Автор: kanes 18.12.09, 17:16 |
Цитата D_KEY @ Так вот и незачем перегружать операторы, которые семантически нельзя представить в виде функций. Кстати где-то видел такую рекомендацию: перегрузку операторов делать так: написать функцию, которая выполняет тоже самое, что и перегружаемый оператор, потом внутри перегрузки использовать эту функцию, честно говоря, не очень понимаю смысла сей рекомендации |
Автор: D_KEY 19.12.09, 18:53 |
Цитата Qraizer @ D_KEY, нельзя заставлять поступать так-то и так-то исключительно из религиозных соображений. Это не религиозные убеждения. Перегрузим ;? Если бы в С++ был способ перегрузить эти операторы и сохранить порядок вычислений, то я бы не был против такой перегрузки. Цитата Тогда уж надо запретить перегружать + как умножение, префиксный ++ как постфиксный итп. Во-первых, это невозможно. Во-вторых, перегрузка этих операторов не оказывает влияние на порядок выполнения. Добавлено Цитата kanes @ Цитата D_KEY @ Так вот и незачем перегружать операторы, которые семантически нельзя представить в виде функций. Кстати где-то видел такую рекомендацию: перегрузку операторов делать так: написать функцию, которая выполняет тоже самое, что и перегружаемый оператор, потом внутри перегрузки использовать эту функцию, честно говоря, не очень понимаю смысла сей рекомендации Возможно это касалось виртуальных методов. Вроде перегрузки оператора вывода(то есть сдвига ). Обычно пишется отдельный виртуальный метод, а оператор переопределяется для ссылки на базовый класс. |
Автор: GoldFinch 19.12.09, 19:59 |
говорили уже, что ; - не оператор. пробел перегрузи. |
Автор: D_KEY 19.12.09, 20:17 |
Так и я о том. Перегружать , также глупо. Добавлено GoldFinch, ты просто рассматриваешь С++ как некую данность, я же хочу понять почему(и зачем) он такой. Пару лет назад, такие книги, как D&E, давали мне нужные ответы, но теперь мне этого недостаточно. Но тут это все-таки не совсем в тему Добавлено Разве можно сказать, что перегрузка , || && вообще является таковой? Их встроенные версии не являются простыми операторами(они вообще по сути своей не являются операторами, хотя и носят такое название), это специальные языковые формы и их нельзя имитировать другими средствами языка. Их "перегрузка" является введением совершенно иной сущности(нового оператора), но с тем же обозначением. Но в С++ нельзя определять собственные операторы, соответственно, даже с этой стороны, такие перегрузки противоречат идеологии языка... |
Автор: GoldFinch 20.12.09, 09:07 |
D_KEY, точно также перегрузка << для потоков меняет сущность оператора сдвига, а также перегрузка % в boost.format, перегрузка & в boost.serialization, и еще куча перегрузок меняющих семантику операторов. |
Автор: kanes 20.12.09, 09:27 |
GoldFinch, сущность поменять можно, но не до абсурда, типа того что перегруженный << на самом деле работает как >> или + работает как умножение |
Автор: sfinae 20.12.09, 10:21 |
Мне показалось что D_KEY делал упор не на изменение семантики самой операции, а на изменение семантики в контексте C++ (из-за изменения порядка выполнения). Например код (который пишут некоторые мои знакомые): <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> foo() && bar(); По сути эквивалентен <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> if(foo())bar(); и гарантирует что bar будет вызван только в случае успешного выполнения foo(). А если для возвращаемого значения bar() перегрузить оператор &&, то эти функции уже могут быть вызваны в любом порядке, и уже к результату применен оператор &&. А это уже не так безобидно как умножать по значку "+". |
Автор: D_KEY 20.12.09, 11:05 |
Не точно также. << как был оператором, так им и остался, порядок вычисления и приоритет будет тем же. || && , ?: - "операторами", в принципе, не являются, поскольку управляют последовательностью вычислений. Это специальные языковые формы. Да, я знаю, что в стандарте они значатся, как операторы. Их "перегрузка" таковой не является, поскольку в этом случае ты вводишь уже "настоящий" оператор(в отличие от встроенных версий || && , ?: ), который просто обозначается теми же символоми. Но это совершенно другая языковая конструкция. Ну не перегрузка это. Добавлено Цитата kanes @ GoldFinch, сущность поменять можно, но не до абсурда, типа того что перегруженный << на самом деле работает как >> или + работает как умножение Это так. Но я не о том Добавлено Цитата sfinae @ Мне показалось что D_KEY делал упор не на изменение семантики самой операции, а на изменение семантики в контексте C++ (из-за изменения порядка выполнения). Ага, примерно так. |
Автор: доцент 22.12.09, 10:22 |
Может кто-нибудь объяснить почему опять убрали хэш-контейнеры из нового стандарта. |
Автор: archimed7592 22.12.09, 10:28 |
Если я не ошибаюсь, то их никуда не убирали. Они присутствуют в TR1, который, насколько я понимаю, полностью был включен в стандарт. Называются они unordered_xxx |
Автор: D_KEY 22.12.09, 12:39 |
Извиняюсь . Поторопился . Цитата Они вполне себе операторы. Операнды у них есть? Есть. Выражения они образуют? Образуют. Чего ещё надо? А можно определение операнда? Просто в контексте С++ у встроенных версий этих операторов операндов нет, поскольку операнды вычисляются до выполнения операции, а для этих операций это не так. Цитата Цитата D_KEY @ Их "перегрузка" является введением совершенно иной сущности(нового оператора), но с тем же обозначением. Вообще-то оператор - это и есть обозначение: Цитата ISO/IEC 24765:2008 (Systems and software engineering — Vocabulary) operator. a mathematical or logical symbol that represents an action to be performed in an operation Правильно. Только встроенные версии рассматриваемых "операторов" не являются операциями(фактически ведут себя как выражения). Или я опять ошибаюсь? Цитата Цитата Но в С++ нельзя определять собственные операторы Нельзя вводить новые обозначения и менять приоритеты. Перегрузка операторов не вводит новых обозначений и приоритеты не меняет. А порядок вычислений менять и заставлять вычислять то, что встроенные версии не вычисляют, можно ? |
Автор: D_KEY 22.12.09, 14:28 |
Цитата Masterkent @ В ISO/IEC 24765:2008 даётся такое определение: Цитата operand. a variable, constant, or function upon which an operation is to be performed И я о том. Цитата Но в C++ операнды не ограничиваются только переменными, константами и функциями. Это могут любые выражения и даже типы. То есть операндом в С++ может являться непосредственно само выражение? Как написать такую функцию? Цитата Где такое правило сформулировано? То есть при вызове функций(или операторов) операнды не обязаны быть вычислены до вызова? Цитата Цитата ISO/IEC 24765:2008 operation. (1) in computer mathematics, the action specified by an operator on one or more operands; (2) in programming, a defined action that can be performed by a computer system К примеру, вот оно описание действия встроенного оператора &&: Цитата 5.14 The operands are both implicitly converted to type bool (clause 4). The result is true if both operands are true and false otherwise. Unlike &, && guarantees left-to-right evaluation: the second operand is not evaluated if the first operand is false. The result is a bool. All side effects of the first expression except for destruction of temporaries (12.2) happen before the second expression is evaluated. Что тут не нравится? То, что это описание "операции" && не соответствует bool * bool -> bool(как должно быть согласно определению "the action specified by an operator on one or more operands"). Вообще, and может быть реализован, как операция над двумя операндами типа bool. Но встроенная версия себя так не ведет. Я не против встроенного поведения, я говорю о том, что перегрузка таких операторов отличается от прочих перегрузок тем, что встроенные версии данных операторов являются специальными языковыми формами, а не обычными операциями(и не могут быть ими заменены). А в результате перегрузки мы вводим именно операцию. |
Автор: sfinae 22.12.09, 14:33 |
Цитата Masterkent @ Unlike &, && guarantees left-to-right evaluation: the second operand is not evaluated if the first operand is false. Вот собственно и описан предмет возмущения D_KEY. |
Автор: Qraizer 22.12.09, 23:20 |
Это-то было понятно с самого начала. Непонятно, с чего бы это должно было быть причиной запрета на их перегрузку. Возможность их перегрузки для пользовательских типов может быть полезна в ряде случаев. Тот факт, что будучи перегруженными, эти операторы будут иметь семантику, отличную от их стандартных форм, во-первых, несложно документируется, во-вторых, и без документирования вполне очевидна. Я склонен считать, что наоборот, стандартные формы этих операторов имеют особенную семантику, что и задокументировано Стандартом. |
Автор: amdei 23.12.09, 00:58 |
Цитата Qraizer @ Я склонен считать, что наоборот, стандартные формы этих операторов имеют особенную семантику Тем более только для типа bool. |
Автор: D_KEY 23.12.09, 07:54 |
Цитата Qraizer @ Это-то было понятно с самого начала. Непонятно, с чего бы это должно было быть причиной запрета на их перегрузку. Я не говорю, что нужно запретить. Я не понимаю, зачем было изначально разрешать. Обратной дороги уже нет. Как и со спецификациями исключений и многим другим... Цитата Возможность их перегрузки для пользовательских типов может быть полезна в ряде случаев. В каких? Цитата Тот факт, что будучи перегруженными, эти операторы будут иметь семантику, отличную от их стандартных форм А я пытаюсь сказать, что встроенные версии вообще не являются операторами. Цитата Так и есть. Стандартные версии - особая языковая форма, а не оператор. Зачем понадобилось давать возможность "пользователям" создавать еще и оператор с таким же обозначением, как встроенная в язык особая форма - непонятно. Это все-равно, что разрешить перегружать макрос функцией.Я склонен считать, что наоборот, стандартные формы этих операторов имеют особенную семантику Можно разрешить добавлять оператор ; или оператор пробела или operator". А что? Просто "стандартные формы этих операторов" будут иметь "особенную семантику". |
Автор: D_KEY 23.12.09, 17:00 |
Можно тогда, на всякий случай, определение функции? А там посмотрим. Математическая запись бинарной операции. |
Автор: D_KEY 24.12.09, 13:07 |
Цитата Masterkent @ Ты можешь внятно растолковать смысл фразы "это описание "операции" && не соответствует bool * bool -> bool"? Составить предложение из букв и прочих символов - не значит написать что-то осмысленное. Если ты не в состоянии что-либо понять, это вовсе не означает, что это что-либо не имеет смысла. Цитирование стандартов не всегда означает понимание лежащих в их основе концепций. Функция, оператор и операция - это, в общем случае, отображения одного множества в другое. Это понятие из математики, но оно справедливо и для программирования, пусть и с некоторыми оговорками для некоторых языков (в данном случае, поскольку мы говорим об элементарных операциях, эти оговорки можно не учитывать). Запись A -> B обозначает отображение множества A в множество B, то есть соответствие каждому из элементов множества A определенному элементу из множества B. A*B обозначает пару элементов множеств A и B соответственно. bool * bool -> bool – обозначает отображение(функцию, операцию, оператор), которое ставит в соответствие паре элементов из множества булевых значений элемент из множества булевых значений. Если в язык встроены ленивые вычисления, а побочных действие нет, то отказ от вычисления второго аргумента логического and абсолютно естественен и по-прежнему соответствует bool * bool -> bool. Если же в язык ленивые вычисления не встроены, но язык предоставляет некоторую специальную языковую конструкцию, которая позволяет откладывать вычисления на тот момент, когда потребуется значение (в принципе, при наличии лямбда функций такая форма имеет очень простую реализацию(но требует или хорошо развитых макросов или введение специальной языковой формы)), то указанное обозначение продолжает иметь силу, правда с некоторыми оговорками. С++ же не имеет ни того, ни другого. Да и не в этом дело. В С++ операции и функции слишком часто используются для своих побочных эффектов, а не только для вычисления значения. Дело не только в "the second operand is not evaluated if the first operand is ...", а в sequence point. Цитата operators can be regrouped according to the usual mathematical rules only where the operators really are associative or commutative . . . Overloaded operators are never assumed to be associative or commutative Цитата A full-expression is an expression that is not a subexpression of another expression … There is a sequence point at the completion of evaluation of each full-expression. Но для рассматриваемых операторов мы имеем: Цитата In the evaluation of each of the expressions a && b a || b a ? b : c a , b using the built-in meaning of the operators in these expressions (5.14, 5.15, 5.16, 5.18), there is a sequence point after the evaluation of the first expression. Это и есть то, что называется особой формой. Данные операции представляют собой специальные выражения, которые рассматриваются особым, отличным от предусмотренного для других выражений, образом. Но, выполняя перегрузку, мы, естественно, убираем эту sequence point: Цитата When one of these operators is overloaded (clause 13) in a valid context, thus designating a user-defined operator function, the expression designates a function invocation, and the operands form an argument list, without an implied sequence point between them Мне кажется нелогично разрешать такую перегрузку. Кроме того, logical AND он и есть logical AND, и смысла ни для каких значений, кроме bool'ов, не имеет. |
Автор: D_KEY 24.12.09, 14:47 |
Цитата Masterkent @ Цитата D_KEY @ Функция, оператор и операция - это, в общем случае, отображения одного множества в другое. Не в общем случае, а только в определённых разделах математики. В императивных языках программирования функции и операторы могут приводить к изменению состояния программы и не иметь результирующего значения. Мы сейчас говорим о выражениях и встроенных операторах или где? Цитата Или, по-твоему, алгебраические определения - единственно верные и на них нужно молиться? Нет. Молиться на какие-либо определения не стоит. Ни на "алгебраические", ни на указанные в стандартах. Но нужно понимать, откуда идут определенные понятия. И поскольку мы говорим о выражениях и элементарных операциях, то все мною сказанное остается корректным. Цитата Так что ты скажешь относительно sequence point? Цитата Как называется && в стандарте?Цитата D_KEY @ Кроме того, logical AND он и есть logical AND, и смысла ни для каких значений, кроме bool'ов, не имеет. Перегруженный оператор && не обязан вычислять "логическое И". Но, конечно, не обязан. |
Автор: Radagast 24.12.09, 17:10 |
Цитата Здесь в полном соответствии со стандартом реализация имеет право вычислить f() во время выполнения программы эээ почему? о_О разве приведенная строка не подпадает под Цитата ? Unlike &, && guarantees left-to-right evaluation: the second operand is not evaluated if the first operand is false. |
Автор: D_KEY 25.12.09, 11:28 |
Цитата Masterkent @ Я ответил на конкретное предложение, где ничего не говорилось про выражения, но говорилось про операторы (без "встроенные"). Я не могу читать твои мысли, а могу только отвечать на то, что ты пишешь. Но сохранять контекст разговора все-таки неплохо бы научится. Цитата очевидно... тоже очевидно. Ну раз очевидно, тогда откуда высказывания о неуместности определений из математики? Цитата Я вообще не понимаю твои рассуждения. Еще разок. Поведение встроенных , && || ?: сильно отличается от поведения остальных операторов, они представляют собой особые языковые формы. Их поведение нельзя имитировать другими языковыми средствами и при их перегрузке нельзя не исказить предусмотренной для них семантики. Цитата Скажу, что не вижу никаких доводов, почему отсу |