Content deleted Content added
KMaster888 (talk | contribs) →See also: subjective |
|||
(67 intermediate revisions by 52 users not shown) | |||
Line 1:
{{Short description|Book by Andrei Alexandrescu}}
{{Use dmy dates|date=September 2023}}
{{Infobox book
| name = Modern C++ Design
| title_orig =
| translator =
| image = Modern C++ Design.jpg
| caption =
| author = [[Andrei Alexandrescu]]
| illustrator =
| cover_artist =
| country =
| language = English
| series =
| subject = [[C++]]
| genre =
| publisher = [[Addison-Wesley]]
| pub_date = 2001
| english_pub_date =
| media_type =
| pages = 323 pp
| isbn = 978-0-201-70431-0
| dewey = 005.13/3 21
| congress = QA76.73.C153 A42 2001
| oclc = 45129236
| preceded_by =
| followed_by =
}}
'''''Modern C++ Design: Generic Programming and Design Patterns Applied''''' is a book
|url=https://www.artima.com/articles/the-most-important-c-booksemeverem|access-date=1 September 2023|title=The Most Important C++ Books...Ever}}</ref>
The book
All of the code described in the book is freely available in his
== Policy-based design ==
'''Policy-based design''', also known as '''policy-based class design''' or '''policy-based programming''', is the term used in ''Modern C++ Design'' for a design approach based on an [[Programming idiom|idiom]] for C++ known as '''policies'''. It has been described as a [[compile-time]] variant of the [[strategy pattern]], and has connections with C++ [[template metaprogramming]]. It was first popularized in C++ by Andrei Alexandrescu with ''Modern C++ Design'' and with his column ''Generic<Programming>'' in the ''[[C/C++ Users Journal]]'', and it is currently closely associated with C++ and [[D (programming language)|D]] as it requires a [[compiler]] with highly [[Robustness (computer science)|robust]] support for [[template (programming)|template]]s, which was not common before about 2003.
Previous examples of this design approach, based on parameterized generic code, include parametric modules (functors) of the [[ML (programming language)|ML]] languages,<ref>[https://www.cl.cam.ac.uk/~lp15/MLbook/PDF/chapter7.pdf Chapter 7. Abstract Types and Functors] cam.ac.uk</ref> and C++ [[Allocator (C++)|allocators]] for memory management policy.
The central idiom in policy-based design is a [[class (computer science)|class]] template (called the ''host'' class), taking several [[data type|type]] [[parameter (computer science)|parameter]]s as input, which are [[instantiation (computer science)|instantiated]] with types selected by the user (called ''policy classes''), each [[implementation|implementing]] a particular implicit [[interface (computer science)|interface]] (called a ''policy''), and [[separation of concerns|encapsulating]] some [[orthogonality#Computer science|orthogonal]] (or mostly orthogonal) aspect of the behavior of the instantiated host class. By supplying a host class combined with a set of different, canned implementations for each policy, a [[library (computing)|library]] or [[module (programming)|module]] can support an [[exponential growth|exponential]] number of different behavior combinations, resolved at compile time, and selected by mixing and matching the different supplied policy classes in the instantiation of the host class template. Additionally, by writing a custom implementation of a given policy, a policy-based library can be used in situations requiring behaviors unforeseen by the library implementor. Even in cases where no more than one implementation of each policy will ever be used, decomposing a class into policies can aid the design process, by increasing modularity and highlighting exactly where orthogonal design decisions have been made.
While assembling software components out of interchangeable modules is a far-fetched concept, policy-based design represents an innovation in a way it applies that concept at the (relatively low) level of defining the behavior of an individual class. Policy classes are similar to [[callback (computer science)|callback]]s, but differ in that, rather than consisting of a single [[subroutine|function]], a policy class will typically contain several related functions ([[method (computer science)|method]]s), often combined with [[state (computer science)|state]] [[Variable (programming)|variables]] or other facilities such as nested types. A policy-based host class can be thought of as a type of [[template metaprogramming|metafunction]], taking a set of behaviors represented by types as input, and returning as output a type representing the result of combining those behaviors into a functioning whole. (Unlike [[Boost C++ Libraries|MPL]] metafunctions, however, the output is usually represented by the instantiated host class itself, rather than a nested output type.)
A key feature of the ''policy'' idiom is that, usually (though it is not strictly necessary), the host class will [[inheritance (object-oriented programming)|derive]] from (make itself a [[subclass (computer science)|child class]] of) each of its policy classes using (public) [[multiple inheritance]]. (Alternatives are for the host class to merely contain a member variable of each policy class type, or else to inherit the policy classes privately; however, inheriting the policy classes publicly has the major advantage that a policy class can add new methods, inherited by the instantiated host class and accessible to its users, which the host class itself need not even know about.) A notable feature of this aspect of the policy idiom is that, relative to [[object-oriented programming]], policies invert the relationship between [[superclass (computer science)|base class]] and derived class - whereas in OOP interfaces are traditionally represented by ([[virtual function#Abstract classes and pure virtual functions|abstract]]) base classes and implementations of interfaces by derived classes, in policy-based design the derived (host) class represents the interfaces and the base (policy) classes implement them. In the case of policies, the public inheritance does not represent an is-a relationship between the host and the policy classes. While this would traditionally be considered evidence of a design defect in OOP contexts, this doesn't apply in the context of the policy idiom.
A disadvantage of policies in their current incarnation is that the policy interface doesn't have a direct, explicit representation in [[source code|code]], but rather is defined implicitly, via [[duck typing]], and must be documented separately and manually, in [[comment (computer programming)|comment]]s. The main idea is to use commonality-variability analysis to divide the type into the fixed implementation and interface, the policy-based class, and the different policies. The trick is to know what goes into the main class, and what policies should one create. The article mentioned above gives the following answer: wherever we would need to make a possible limiting design decision, we should postpone that decision, we should delegate it to an appropriately named policy.
Policy classes can contain implementation, type definitions and so forth. Basically, the designer of the main template class will define what the policy classes should provide, what customization points they need to implement.
It may be a delicate task to create a good set of policies, just the right number (e.g., the minimum necessary). The different customization points, which belong together, should go into one policy argument, such as storage policy, validation policy and so forth. Graphic designers are able to give a name to their policies, which represent concepts, and not those which represent operations or minor implementation details.
Policy-based design may incorporate other useful techniques. For example, the [[template method pattern]] can be reinterpreted for compile time, so that a main class has a [[skeleton algorithm]], which{{snd}}at customization points{{snd}}calls the appropriate functions of some of the policies.
This will be achieved dynamically by [[concepts (C++)|concepts]]<ref>[http://www.stroustrup.com/good_concepts.pdf Concepts: The Future of Generic Programming] stroustrup.com</ref> in future versions of C++.
=== Simple example ===
Presented below is a simple (contrived) example of a C++ [[hello world program]], where the text to be printed and the method of printing it are decomposed using policies. In this example, ''HelloWorld'' is a host class where it takes two policies, one for specifying how a message should be shown and the other for the actual message being printed. Note that the generic implementation is in <code>Run</code> and therefore the code is unable to be compiled unless both policies (<code>Print</code> and <code>Message</code>) are provided.
<syntaxhighlight lang=cpp>
#include <iostream>
#include <string>
template <typename OutputPolicy, typename LanguagePolicy>
class HelloWorld : private OutputPolicy, private LanguagePolicy {
public:
// Behavior method.
void Run() const {
// Two policy methods.
Print(Message());
}
private:
using LanguagePolicy::Message;
using OutputPolicy::Print;
};
class OutputPolicyWriteToCout {
protected:
void Print(std::string&& message) const {
std::cout << message << std::endl;
}
};
class LanguagePolicyEnglish {
protected:
std::string Message() const { return "Hello, World!"; }
};
class LanguagePolicyGerman {
protected:
std::string Message() const { return "Hallo Welt!"; }
};
int main() {
// Example 1
using HelloWorldEnglish = HelloWorld<OutputPolicyWriteToCout, LanguagePolicyEnglish>;
HelloWorldEnglish hello_world;
hello_world.Run(); // Prints "Hello, World!".
// Example 2
// Does the same, but uses another language policy.
using HelloWorldGerman = HelloWorld<OutputPolicyWriteToCout, LanguagePolicyGerman>;
HelloWorldGerman hello_world2;
hello_world2.Run(); // Prints "Hallo Welt!".
}
</syntaxhighlight>
Designers can easily write more <code>OutputPolicy</code>s by adding new classes with the member function <code>Print</code> and take those as new <code>OutputPolicy</code>s.
==Loki library==
'''Loki''' is a [[C++]] [[Library (computer science)|software library]] written by [[Andrei Alexandrescu]] as part of his book ''Modern C++ Design''.
The library makes extensive use of C++ [[template metaprogramming]] and implements several commonly used tools: [[typelist]], [[Function object|functor]], [[Singleton pattern|singleton]], [[smart pointer]], [[Factory object|object factory]], [[Visitor pattern|visitor]] and [[Multiple dispatch|multimethods]].
Originally the library was only compatible with two of the most standard conforming C++ compilers ([[CodeWarrior]] and [[Comeau C/C++]]): later efforts have made it usable with a wide array of compilers (including older [[Visual C++|Visual C++ 6.0]], [[C++ Builder|Borland C++ Builder 6.0]], [[Clang]] and [[GNU Compiler Collection|GCC]]). Compiler vendors used Loki as a compatibility benchmark, further increasing the number of compliant compilers.<ref>C++ and Beyond 2011: "Ask Us Anything" session, http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2011-Scott-Andrei-and-Herb-Ask-Us-Anything at 51:40-51:51</ref>
Maintenance and further development of Loki has been continued through an open-source community led by [[Peter Kümmel]] and [[Richard Sposato]] as a SourceForge project. Ongoing contributions by many people have improved the overall robustness and functionality of the library. Loki is not tied to the book anymore as it already has a lot of new components (e.g. StrongPtr, Printf, and Scopeguard). Loki inspired similar tools and functionality now also present in the [[Boost (C++ libraries)|Boost]] library collection.{{Citation needed|date=November 2010}}
==See also==
{{Portal|Free and open-source software}}
* [[Mixin]]
==References==
{{reflist}}
==External
* [http://erdani.org
* [http://www.informit.com/articles/article.aspx?p=25264 Smart Pointers] (sample chapter from the book)
* {{SourceForge|loki-lib|Loki}}
* [http://www.awprofessional.com/content/images/0201704315/sourcecode/loki.zip Original source code from the book publisher]
[[Category:2001 non-fiction books]]
[[Category:
|