Эффективный и современный С++. 42 рекомендации по использованию С++11 и С++14 - [84]
>!
” в начале выражения. Мы хотим, чтобы типы >Person
и >T
не совпадали.) Это близко к тому, что нам надо, но не совсем верно, поскольку, как поясняет раздел 5.6, тип, выведенный для универсальной ссылки, инициализированной lvalue, всегда является lvalue-ссылкой. Это означает, что в коде наподобие>Person p("Nancy");
>auto cloneOfP(p); // Инициализация с помощью lvalue
тип >T
в универсальном конструкторе будет выведен как >Person&
. Типы >Person
и >Person&
— разные, и результат >std::is_same
отражает этот факт: значение >std::is_same
ложно.
Если разобраться, что означает, что шаблонный конструктор в классе >Person
должен быть включен только тогда, когда >T
не является >Person
, то мы поймем, что, глядя на >T
, мы хотим игнорировать следующее.
• Ссылки. С точки зрения определения, должен ли быть включен конструктор с универсальной ссылкой, типы >Person
, >Person&
и >Person&&
должны рассматриваться как идентичные типу >Person
.
• Модификаторы>const
и>volatile
. С той же точки зрения типы >const Person
, >volatile Person
и >const volatile Person
должны рассматриваться как идентичные типу >Person
.
Это означает, что нам нужен способ удалить все ссылки, >const
и >volatile
из типа >T
перед тем как выяснять, совпадает ли он с типом >Person
. И вновь на выручку приходит стандартная библиотека, предоставляя шаблон >std::decay
. Тип >std::decay
представляет собой то же самое, что и тип >T
, но из него удалены все ссылки и квалификаторы >const
и >volatile
. (Я немного вас обманул, потому что >std::decay
, кроме того, превращает массивы и типы функций в указатели (см. раздел 1.1), но для наших целей можно считать, что >std::decay
ведет себя так, как я описал.) Условие, которое должно выполняться для включения рассматриваемого конструктора, имеет вид
>!std::is_same
т.e. >Person
не совпадает с типом >T
, без учета всех ссылок и квалификаторов >const
и >volatile
. (Как поясняется в разделе 3.3, ключевое слово typename перед >std::decay
необходимо, поскольку тип >std::decay
зависит от параметра шаблона >T
.)
Вставка этого условия в шаблон >std::enable_if
выше, а также форматирование результата для того, чтобы проще понять взаимоотношения между частями кода, дает следующее объявление конструктора с прямой передачей класса >Person
:
>class Person {
>public:
> template<
> typename T,
> typename = typename std::enable_if<
> !std::is_same
> typename std::decay
> >::value
> >::type
> >
> explicit Person(T&& n);
>};
Если вы никогда ранее не видели ничего подобного, не пугайтесь. Есть причина, по которой я оставил этот метод напоследок. Если для того, чтобы избежать смешивания универсальных ссылок и перегрузки вы можете использовать один из прочих методов (а это почти всегда возможно), вы должны это сделать. Тем не менее, если вы привыкнете к функциональному синтаксису и множеству угловых скобок, это не так плохо. Кроме того, это позволяет получить поведение, к которому вы стремитесь. С учетом приведенного выше объявления построение объекта >Person
из другого объекта >Person
(lvalue или rvalue, с квалификатором >const
или без него, с квалификатором >volatile
или без него) никогда не вызовет конструктор, принимающий универсальную ссылку.
Мы добились успеха? Дело сделано?
Пока что нет. Не спешите праздновать. Раздел 5.4 все еще посылает нам свои приветы. Нам надо заткнуть этот фонтан окончательно.
Предположим, что класс, производный от >Person
, реализует операции копирования и перемещения традиционным способом:
>class SpecialPerson: public Person {
>public:
> SpecialPerson (const SpecialPerson& rhs) // Копирующий
> : Person(rhs) // конструктор; вызывает конструктор
> { … } // базового класса с прямой передачей!
> SpecialPerson(SpecialPerson&& rhs) // Перемещающий
> : Person(std::move(rhs)) // конструктор; вызывает конструктор
> { … } // базового класса с прямой передачей!
>};
Это тот же код, который вы видели ранее, в конце предыдущего раздела, включая комментарии, увы, оставшиеся справедливыми. Копируя или перемещая объект >SpecialPerson
, мы ожидаем, что части базового класса будут скопированы или перемещены с помощью копирующего или, соответственно, перемещающего конструктора базового класса. Однако в этих функциях мы передаем объекты >SpecialPerson
конструкторам базового класса, а поскольку >SpecialPerson
не совпадает с >Person
(даже после применения >std::decay
), конструктор с универсальной ссылкой в базовом классе оказывается включенным и без проблем проходит проверку на идеальное совпадение с аргументом >SpecialPerson
. Это точное соответствие лучше преобразования производного класса в базовый, необходимого для связывания объекта >SpecialPerson
с параметром >Person
в копирующем и перемещающем конструкторах класса >Person
, так что при имеющемся коде копирование и перемещение объектов >SpecialPerson
будет использовать для копирования и перемещения частей базового класса конструктор с универсальной ссылкой класса >Person
! Это чудное ощущение дежавю раздела 5.4…
В этой книге известный автор Скотт Мейерс раскрывает секреты настоящих мастеров, позволяющие добиться максимальной эффективности при работе с библиотекой STL.Во многих книгах описываются возможности STL, но только в этой рассказано о том, как работать с этой библиотекой. Каждый из 50 советов книги подкреплен анализом и убедительными примерами, поэтому читатель не только узнает, как решать ту или иную задачу, но и когда следует выбирать то или иное решение — и почему именно такое.
Когда приходится инкапсулировать, то иногда лучше меньше, чем большеЯ начну со следующего утверждения: Если вы пишете функцию, которая может быть выполнена или как метод класса, или быть внешней по отношению к классу, Вы должны предпочесть ее реализацию без использования метода. Такое решение увеличивает инкапсуляцию класса. Когда Вы думаете об использовании инкапсуляции, Вы должны думать том, чтобы не использовать методы.Удивлены? Читайте дальше.
Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.
Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.