Scott Meyers - Effective Modern C++

Здесь есть возможность читать онлайн «Scott Meyers - Effective Modern C++» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Город: Sebastopol, Год выпуска: 2014, ISBN: 2014, Издательство: O’Reilly, Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

Effective Modern C++: краткое содержание, описание и аннотация

Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Effective Modern C++»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.

Coming to grips with C++11 and C++14 is more than a matter of familiarizing yourself with the features they introduce (e.g., auto type declarations, move semantics, lambda expressions, and concurrency support). The challenge is learning to use those features
— so that your software is correct, efficient, maintainable, and portable. That's where this practical book comes in. It describes how to write truly great software using C++11 and C++14 — i.e., using
C++.
Topics include:
■ The pros and cons of braced initialization,
specifications, perfect forwarding, and smart pointer make functions
■ The relationships among
,
, rvalue references, and universal references
■ Techniques for writing clear, correct,
lambda expressions
■ How
differs from
, how each should be used, and how they relate to C++'s concurrency API
■ How best practices in “old” C++ programming (i.e., C++98) require revision for software development in modern C++
Effective Modern C++ For more than 20 years,
'
books (
,
, and
) have set the bar for C++ programming guidance. His clear, engaging explanations of complex technical material have earned him a worldwide following, keeping him in demand as a trainer, consultant, and conference presenter. He has a Ph.D. in Computer Science from Brown University.
“After I learned the C++ basics, I then learned how to use C++ in production code from Meyers' series of Effective C++ books. Effective Modern C++ is the most important how-to book for advice on key guidelines, styles, and idioms to use modern C++ effectively and well. Don't own it yet? Buy this one. Now.”
Herb Sutter
Chair of ISO C++ Standards Committee and C++ Software Architect at Microsoft

Effective Modern C++ — читать онлайн бесплатно полную книгу (весь текст) целиком

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Effective Modern C++», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

In truth, the real problem is not that the compiler-generated functions sometimes bypass the tag dispatch design, it's that they don't always pass it by. You virtually always want the copy constructor for a class to handle requests to copy lvalues of that type, but, as Item 26demonstrates, providing a constructor taking a universal reference causes the universal reference constructor (rather than the copy constructor) to be called when copying non -constlvalues. That Item also explains that when a base class declares a perfect-forwarding constructor, that constructor will typically be called when derived classes implement their copy and move constructors in the conventional fashion, even though the correct behavior is for the base class's copy and move constructors to be invoked.

For situations like these, where an overloaded function taking a universal reference is greedier than you want, yet not greedy enough to act as a single dispatch function, tag dispatch is not the droid you're looking for. You need a different technique, one that lets you rachet down the conditions under which the function template that the universal reference is part of is permitted to be employed. What you need, my friend, is std::enable_if.

std::enable_ifgives you a way to force compilers to behave as if a particular template didn't exist. Such templates are said to be disabled . By default, all templates are enabled , but a template using std::enable_ifis enabled only if the condition specified by std::enable_ifis satisfied. In our case, we'd like to enable the Personperfect-forwarding constructor only if the type being passed isn't Person. If the type being passed is Person, we want to disable the perfect-forwarding constructor (i.e., cause compilers to ignore it), because that will cause the class's copy or move constructor to handle the call, which is what we want when a Personobject is initialized with another Person.

The way to express that idea isn't particularly difficult, but the syntax is off-putting, especially if you've never seen it before, so I'll ease you into it. There's some boilerplate that goes around the condition part of std::enable_if, so we'll start with that. Here's the declaration for the perfect-forwarding constructor in Person, showing only as much of the std::enable_ifas is required simply to use it. I'm showing only the declaration for this constructor, because the use of std::enable_ifhas no effect on the function's implementation. The implementation remains the same as in Item 26.

class Person {

public:

template

typename = typename std::enable_if< condition >::type>

explicit Person(T&& n);

};

To understand exactly what's going on in the highlighted text, I must regretfully suggest that you consult other sources, because the details take a while to explain, and there's just not enough space for it in this book. (During your research, look into “SFINAE” as well as std::enable_if, because SFINAE is the technology that makes std::enable_ifwork.) Here, I want to focus on expression of the condition that will control whether this constructor is enabled.

The condition we want to specify is that Tisn't Person, i.e., that the templatized constructor should be enabled only if T is a type other than Person. Thanks to a type trait that determines whether two types are the same ( std::is_same), it would seem that the condition we want is !std::is_same::value. (Notice the “ !” at the beginning of the expression. We want for Personand Tto not be the same.) This is close to what we need, but it's not quite correct, because, as Item 28explains, the type deduced for a universal reference initialized with an lvalue is always an lvalue reference. That means that for code like this,

Person p("Nancy");

auto cloneOfP(p); // initialize from lvalue

the type Tin the universal constructor will be deduced to be Person&. The types Personand Person&are not the same, and the result of std::is_samewill reflect that: std::is_same::valueis false.

If we think more precisely about what we mean when we say that the templatized constructor in Personshould be enabled only if Tisn't Person, we'll realize that when we're looking at T, we want to ignore

Whether it's a reference. For the purpose of determining whether the universal reference constructor should be enabled, the types Person, Person&, and Person&&are all the same as Person.

Whether it's const or volatile . As far as we're concerned, a const Personand a volatile Personand a const volatile Personare all the same as a Person.

This means we need a way to strip any references, consts, and volatiles from Tbefore checking to see if that type is the same as Person. Once again, the Standard Library gives us what we need in the form of a type trait. That trait is std::decay. std::decay::typeis the same as T, except that references and cv-qualifiers (i.e., constor volatilequalifiers) are removed. (I'm fudging the truth here, because std::decay, as its name suggests, also turns array and function types into pointers (see Item 1), but for purposes of this discussion, std::decaybehaves as I've described.) The condition we want to control whether our constructor is enabled, then, is

!std::is_same::type>::value

i.e., Personis not the same type as T, ignoring any references or cv-qualifiers. (As Item 9explains, the “ typename” in front of std::decayis required, because the type std::decay::typedepends on the template parameter T.)

Inserting this condition into the std::enable_ifboilerplate above, plus formatting the result to make it easier to see how the pieces fit together, yields this declaration for Person's perfect-forwarding constructor:

class Person {

public:

template<

typename T,

typename = typename std::enable_if<

!std::is_same

typename std::decay::type

>::value

>::type

>

explicit Person(T&& n);

};

If you've never seen anything like this before, count your blessings. There's a reason I saved this design for last. When you can use one of the other mechanisms to avoid mixing universal references and overloading (and you almost always can), you should. Still, once you get used to the functional syntax and the proliferation of angle brackets, it's not that bad. Furthermore, this gives you the behavior you've been striving for. Given the declaration above, constructing a Personfrom another Person— lvalue or rvalue, constor non- const, volatileor non- volatile— will never invoke the constructor taking a universal reference.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Похожие книги на «Effective Modern C++»

Представляем Вашему вниманию похожие книги на «Effective Modern C++» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


Отзывы о книге «Effective Modern C++»

Обсуждение, отзывы о книге «Effective Modern C++» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x