![]() |
От: | Masterkent | |
Дата: | 27.03.10 18:35 | ||
Оценка: |
32 (6)
![]() |
Скрытый текст | |
1) Ограничения на использование выражений типа void. N3035 — 3.9.1/9: Эти два соседние предложения противоречат друг другу: из первого следует, что выражение типа void можно преобразовать к типу void, а из второго следует, что такое преобразование недопустимо (т.к. не подпадает ни под один из пяти вариантов легального использования выражений типа void). Забавно, не правда ли? Но это ещё не всё. Должно ли вот такое дело
работать, если тип выражения fn(std::forward<Types>(args)...) — это void? Фигушки. Применение decltype к выражениям типа void незаконно (такое использование выражений типа void не значится в списке легальных — см. выше). Сильно сомневаюсь, что на это ограничение есть какие-то веские причины — скорее всего, про данный случай просто забыли. 2) Неявное добавление "(*this)." Допустим, у нас есть структура S c non-static data member-ом m и мы хотим узнать размер S::m. Хорошая новость: теперь вместо зубодробительной конструкции sizeof ((S*)0)->m мы сможем использовать просто sizeof S::m. N3035 — 5.1.1/10: Плохая новость: причудливые правила не разрешают использование таких конструкций в нестатических функциях-членах некоторых классов:
Всё дело в том, что по новым правилам любой non-static member в любой non-static member function (независимо от того, к какому классу принадлежит эта функция) должен неявно предваряться конструкцией "(*this).". N3035 — 9.3.1/3: Т.е. в нашем случае выражение B::m внутри функции X::g неявно трансформируется в (*this).B::m. Естественно, добавление "(*this)." к совершенно чужому member-у незаконно. Странное дело получается: мы, вроде бы, "(*this)." не пишем, но оно само собой приписывается и делает нашу программу некорректной. Возникает естественный вопрос: откуда взялись такие правила? Как оказалось, это заслуга автора, который захотел по-быстрому решить проблему, описанную в DR 515. Но что сподвигло его на столь необычное разрешение проблемы (добавлять (*this). к чему ни попадя), остаётся для меня загадкой. 3) Целые статические константы, объявленные с инициализатором в определении класса, всё ещё нуждаются в определении вне класса при их использовании. В следующем примере
попытка формирования ссылки на неопределённый объект может породить ошибку трансляции. По правилам C++03 даже такая программа некорректна:
Непременно нужно внешнее определение, а то ж бедный транслятор программы ни за что не догадается, что кто-то использует адрес переменной и под неё-таки нужно выделить маленький клочок памяти (а в случаях, когда адрес не используется, жадно сэкономить несколько байтиков). Вместо того чтобы раз и навсегда избавить программиста от лишней писанины во всех подобных случаях (такие переменные можно было бы считать определёнными независимо от наличия внешнего определения), комитет решил ограничиться лишь сокращением случаев, относящихся к использованию объектов (требующих присутствие определения). 4) Использование длинных синтаксических конструкций. Шаблоны в <type_traits> — это какое-то убожество. Если в Boost ещё хоть как-то боролись с синтаксическими нагромождениями (например, см. boost::enable_if vs boost::enable_if_c), то здесь же всюду нужно дописывать ::value и ::type (в последнем случае ещё и typename приходится использовать, если есть зависимость от параметров шаблона). Что, к примеру, мешает определить is_pointer и enable_if следующим образом?
Мы могли бы использовать эти шаблоны примерно так:
А вот так выглядит аналогичное использование стандартных шаблонов в их нынешнем виде:
Как видно, комитет заметно усовершенствовал ядро языка, но довести до ума стандартную библиотеку пороху не хватило. | |