123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
- <title>Base_From_Member</title>
- <link rel="stylesheet" href="../../../../doc/src/boostbook.css" type="text/css">
- <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
- <link rel="home" href="base_from_member.html" title="Base_From_Member">
- </head>
- <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
- <table cellpadding="2" width="100%"><tr>
- <td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../boost.png"></td>
- <td align="center"><a href="../../../../index.html">Home</a></td>
- <td align="center"><a href="../../../../libs/libraries.htm">Libraries</a></td>
- <td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
- <td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
- <td align="center"><a href="../../../../more/index.htm">More</a></td>
- </tr></table>
- <hr>
- <div class="spirit-nav"></div>
- <div class="article">
- <div class="titlepage">
- <div>
- <div><h2 class="title">
- <a name="base_from_member"></a>Base_From_Member</h2></div>
- <div><div class="authorgroup"><div class="author"><h3 class="author">
- <span class="firstname">Daryle</span> <span class="surname">Walker</span>
- </h3></div></div></div>
- <div><p class="copyright">Copyright © 2001, 2003, 2004, 2012 Daryle
- Walker</p></div>
- <div><div class="legalnotice">
- <a name="base_from_member.legal"></a><p>
- Distributed under the Boost Software License, Version 1.0. (See accompanying
- file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
- </p>
- </div></div>
- </div>
- <hr>
- </div>
- <div class="toc">
- <p><b>Table of Contents</b></p>
- <dl class="toc">
- <dt><span class="section"><a href="base_from_member.html#base_from_member.rationale">Rationale</a></span></dt>
- <dt><span class="section"><a href="base_from_member.html#base_from_member.synopsis">Synopsis</a></span></dt>
- <dt><span class="section"><a href="base_from_member.html#base_from_member.usage">Usage</a></span></dt>
- <dt><span class="section"><a href="base_from_member.html#base_from_member.example">Example</a></span></dt>
- <dt><span class="section"><a href="base_from_member.html#base_from_member.acknowledgments">Acknowledgments</a></span></dt>
- </dl>
- </div>
- <div class="section">
- <div class="titlepage"><div><div><h2 class="title" style="clear: both">
- <a name="base_from_member.rationale"></a><a class="link" href="base_from_member.html#base_from_member.rationale" title="Rationale">Rationale</a>
- </h2></div></div></div>
- <p>
- When developing a class, sometimes a base class needs to be initialized with
- a member of the current class. As a naïve example:
- </p>
- <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">streambuf</span><span class="special">></span> <span class="comment">/* for std::streambuf */</span>
- <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">ostream</span><span class="special">></span> <span class="comment">/* for std::ostream */</span>
- <span class="keyword">class</span> <span class="identifier">fdoutbuf</span>
- <span class="special">:</span> <span class="keyword">public</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">streambuf</span>
- <span class="special">{</span>
- <span class="keyword">public</span><span class="special">:</span>
- <span class="keyword">explicit</span> <span class="identifier">fdoutbuf</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">);</span>
- <span class="comment">//...</span>
- <span class="special">};</span>
- <span class="keyword">class</span> <span class="identifier">fdostream</span>
- <span class="special">:</span> <span class="keyword">public</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span>
- <span class="special">{</span>
- <span class="keyword">protected</span><span class="special">:</span>
- <span class="identifier">fdoutbuf</span> <span class="identifier">buf</span><span class="special">;</span>
- <span class="keyword">public</span><span class="special">:</span>
- <span class="keyword">explicit</span> <span class="identifier">fdostream</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">)</span>
- <span class="special">:</span> <span class="identifier">buf</span><span class="special">(</span> <span class="identifier">fd</span> <span class="special">),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span><span class="special">(</span> <span class="special">&</span><span class="identifier">buf</span> <span class="special">)</span> <span class="special">{}</span>
- <span class="comment">//...</span>
- <span class="special">};</span>
- </pre>
- <p>
- This is undefined because C++'s initialization order mandates that the base
- class is initialized before the member it uses. <a href="http://www.moocat.org" target="_top">R.
- Samuel Klatchko</a> developed a way around this by using the initialization
- order in his favor. Base classes are intialized in order of declaration, so
- moving the desired member to another base class, that is initialized before
- the desired base class, can ensure proper initialization.
- </p>
- <p>
- A custom base class can be made for this idiom:
- </p>
- <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">streambuf</span><span class="special">></span> <span class="comment">/* for std::streambuf */</span>
- <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">ostream</span><span class="special">></span> <span class="comment">/* for std::ostream */</span>
- <span class="keyword">class</span> <span class="identifier">fdoutbuf</span>
- <span class="special">:</span> <span class="keyword">public</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">streambuf</span>
- <span class="special">{</span>
- <span class="keyword">public</span><span class="special">:</span>
- <span class="keyword">explicit</span> <span class="identifier">fdoutbuf</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">);</span>
- <span class="comment">//...</span>
- <span class="special">};</span>
- <span class="keyword">struct</span> <span class="identifier">fdostream_pbase</span>
- <span class="special">{</span>
- <span class="identifier">fdoutbuf</span> <span class="identifier">sbuffer</span><span class="special">;</span>
- <span class="keyword">explicit</span> <span class="identifier">fdostream_pbase</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">)</span>
- <span class="special">:</span> <span class="identifier">sbuffer</span><span class="special">(</span> <span class="identifier">fd</span> <span class="special">)</span> <span class="special">{}</span>
- <span class="special">};</span>
- <span class="keyword">class</span> <span class="identifier">fdostream</span>
- <span class="special">:</span> <span class="keyword">private</span> <span class="identifier">fdostream_pbase</span>
- <span class="special">,</span> <span class="keyword">public</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span>
- <span class="special">{</span>
- <span class="keyword">typedef</span> <span class="identifier">fdostream_pbase</span> <span class="identifier">pbase_type</span><span class="special">;</span>
- <span class="keyword">typedef</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="identifier">base_type</span><span class="special">;</span>
- <span class="keyword">public</span><span class="special">:</span>
- <span class="keyword">explicit</span> <span class="identifier">fdostream</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">)</span>
- <span class="special">:</span> <span class="identifier">pbase_type</span><span class="special">(</span> <span class="identifier">fd</span> <span class="special">),</span> <span class="identifier">base_type</span><span class="special">(</span> <span class="special">&</span><span class="identifier">sbuffer</span> <span class="special">)</span> <span class="special">{}</span>
- <span class="comment">//...</span>
- <span class="special">};</span>
- </pre>
- <p>
- Other projects can use similar custom base classes. The technique is basic
- enough to make a template, with a sample template class in this library. The
- main template parameter is the type of the enclosed member. The template class
- has several (explicit) constructor member templates, which implicitly type
- the constructor arguments and pass them to the member. The template class uses
- implicit copy construction and assignment, cancelling them if the enclosed
- member is non-copyable.
- </p>
- <p>
- Manually coding a base class may be better if the construction and/or copying
- needs are too complex for the supplied template class, or if the compiler is
- not advanced enough to use it.
- </p>
- <p>
- Since base classes are unnamed, a class cannot have multiple (direct) base
- classes of the same type. The supplied template class has an extra template
- parameter, an integer, that exists solely to provide type differentiation.
- This parameter has a default value so a single use of a particular member type
- does not need to concern itself with the integer.
- </p>
- </div>
- <div class="section">
- <div class="titlepage"><div><div><h2 class="title" style="clear: both">
- <a name="base_from_member.synopsis"></a><a class="link" href="base_from_member.html#base_from_member.synopsis" title="Synopsis">Synopsis</a>
- </h2></div></div></div>
- <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">type_traits</span><span class="special">></span> <span class="comment">/* exposition only */</span>
- <span class="preprocessor">#ifndef</span> <span class="identifier">BOOST_BASE_FROM_MEMBER_MAX_ARITY</span>
- <span class="preprocessor">#define</span> <span class="identifier">BOOST_BASE_FROM_MEMBER_MAX_ARITY</span> <span class="number">10</span>
- <span class="preprocessor">#endif</span>
- <span class="keyword">template</span> <span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">MemberType</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">UniqueID</span> <span class="special">=</span> <span class="number">0</span> <span class="special">></span>
- <span class="keyword">class</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span>
- <span class="special">{</span>
- <span class="keyword">protected</span><span class="special">:</span>
- <span class="identifier">MemberType</span> <span class="identifier">member</span><span class="special">;</span>
- <span class="preprocessor">#if</span> <span class="emphasis"><em>C++11 is in use</em></span>
- <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="special">...</span><span class="identifier">T</span> <span class="special">></span>
- <span class="keyword">explicit</span> <span class="keyword">constexpr</span> <span class="identifier">base_from_member</span><span class="special">(</span> <span class="identifier">T</span><span class="special">&&</span> <span class="special">...</span><span class="identifier">x</span> <span class="special">)</span>
- <span class="keyword">noexcept</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_nothrow_constructible</span><span class="special"><</span><span class="identifier">MemberType</span><span class="special">,</span> <span class="identifier">T</span><span class="special">...>::</span><span class="identifier">value</span> <span class="special">);</span>
- <span class="preprocessor">#else</span>
- <span class="identifier">base_from_member</span><span class="special">();</span>
- <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">T1</span> <span class="special">></span>
- <span class="keyword">explicit</span> <span class="identifier">base_from_member</span><span class="special">(</span> <span class="identifier">T1</span> <span class="identifier">x1</span> <span class="special">);</span>
- <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">T1</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T2</span> <span class="special">></span>
- <span class="identifier">base_from_member</span><span class="special">(</span> <span class="identifier">T1</span> <span class="identifier">x1</span><span class="special">,</span> <span class="identifier">T2</span> <span class="identifier">x2</span> <span class="special">);</span>
- <span class="comment">//...</span>
- <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">T1</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T2</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T3</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T4</span><span class="special">,</span>
- <span class="keyword">typename</span> <span class="identifier">T5</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T6</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T7</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T8</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T9</span><span class="special">,</span>
- <span class="keyword">typename</span> <span class="identifier">T10</span> <span class="special">></span>
- <span class="identifier">base_from_member</span><span class="special">(</span> <span class="identifier">T1</span> <span class="identifier">x1</span><span class="special">,</span> <span class="identifier">T2</span> <span class="identifier">x2</span><span class="special">,</span> <span class="identifier">T3</span> <span class="identifier">x3</span><span class="special">,</span> <span class="identifier">T4</span> <span class="identifier">x4</span><span class="special">,</span> <span class="identifier">T5</span> <span class="identifier">x5</span><span class="special">,</span> <span class="identifier">T6</span> <span class="identifier">x6</span><span class="special">,</span> <span class="identifier">T7</span> <span class="identifier">x7</span><span class="special">,</span>
- <span class="identifier">T8</span> <span class="identifier">x8</span><span class="special">,</span> <span class="identifier">T9</span> <span class="identifier">x9</span><span class="special">,</span> <span class="identifier">T10</span> <span class="identifier">x10</span> <span class="special">);</span>
- <span class="preprocessor">#endif</span>
- <span class="special">};</span>
- <span class="keyword">template</span> <span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">MemberType</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">UniqueID</span> <span class="special">></span>
- <span class="keyword">class</span> <span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">MemberType</span><span class="special">&,</span> <span class="identifier">UniqueID</span><span class="special">></span>
- <span class="special">{</span>
- <span class="keyword">protected</span><span class="special">:</span>
- <span class="identifier">MemberType</span><span class="special">&</span> <span class="identifier">member</span><span class="special">;</span>
- <span class="keyword">explicit</span> <span class="keyword">constexpr</span> <span class="identifier">base_from_member</span><span class="special">(</span> <span class="identifier">MemberType</span><span class="special">&</span> <span class="identifier">x</span> <span class="special">)</span>
- <span class="keyword">noexcept</span><span class="special">;</span>
- <span class="special">};</span>
- </pre>
- <p>
- The class template has a first template parameter <code class="computeroutput"><span class="identifier">MemberType</span></code>
- representing the type of the based-member. It has a last template parameter
- <code class="computeroutput"><span class="identifier">UniqueID</span></code>, that is an <code class="computeroutput"><span class="keyword">int</span></code>, to differentiate between multiple base
- classes that use the same based-member type. The last template parameter has
- a default value of zero if it is omitted. The class template has a protected
- data member called <code class="computeroutput"><span class="identifier">member</span></code> that
- the derived class can use for later base classes (or itself).
- </p>
- <p>
- If the appropriate features of C++11 are present, there will be a single constructor
- template. It implements <span class="emphasis"><em>perfect forwarding</em></span> to the best
- constructor call of <code class="computeroutput"><span class="identifier">member</span></code>
- (if any). The constructor template is marked both <code class="computeroutput"><span class="keyword">constexpr</span></code>
- and <code class="computeroutput"><span class="keyword">explicit</span></code>. The former will
- be ignored if the corresponding inner constructor call (of <code class="computeroutput"><span class="identifier">member</span></code>)
- does not have the marker. The latter binds the other way; always taking effect,
- even when the inner constructor call does not have the marker. The constructor
- template propagates the <code class="computeroutput"><span class="keyword">noexcept</span></code>
- status of the inner constructor call. (The constructor template has a trailing
- parameter with a default value that disables the template when its signature
- is too close to the signatures of the automatically-defined non-template copy-
- and/or move-constructors of <code class="computeroutput"><span class="identifier">base_from_member</span></code>.)
- </p>
- <p>
- On earlier-standard compilers, there is a default constructor and several constructor
- member templates. These constructor templates can take as many arguments (currently
- up to ten) as possible and pass them to a constructor of the data member.
- </p>
- <p>
- A specialization for member references offers a single constructor taking a
- <code class="computeroutput"><span class="identifier">MemberType</span><span class="special">&</span></code>,
- which is the only way to initialize a reference.
- </p>
- <p>
- Since C++ does not allow any way to explicitly state the template parameters
- of a templated constructor, make sure that the arguments are already close
- as possible to the actual type used in the data member's desired constructor.
- Explicit conversions may be necessary.
- </p>
- <p>
- The <code class="computeroutput"><span class="identifier">BOOST_BASE_FROM_MEMBER_MAX_ARITY</span></code>
- macro constant specifies the maximum argument length for the constructor templates.
- The constant may be overridden if more (or less) argument configurations are
- needed. The constant may be read for code that is expandable like the class
- template and needs to maintain the same maximum size. (Example code would be
- a class that uses this class template as a base class for a member with a flexible
- set of constructors.) This constant is ignored when C++11 features are present.
- </p>
- </div>
- <div class="section">
- <div class="titlepage"><div><div><h2 class="title" style="clear: both">
- <a name="base_from_member.usage"></a><a class="link" href="base_from_member.html#base_from_member.usage" title="Usage">Usage</a>
- </h2></div></div></div>
- <p>
- With the starting example, the <code class="computeroutput"><span class="identifier">fdoutbuf</span></code>
- sub-object needs to be encapsulated in a base class that is inheirited before
- <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span></code>.
- </p>
- <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">utility</span><span class="special">/</span><span class="identifier">base_from_member</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
- <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">streambuf</span><span class="special">></span> <span class="comment">// for std::streambuf</span>
- <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">ostream</span><span class="special">></span> <span class="comment">// for std::ostream</span>
- <span class="keyword">class</span> <span class="identifier">fdoutbuf</span>
- <span class="special">:</span> <span class="keyword">public</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">streambuf</span>
- <span class="special">{</span>
- <span class="keyword">public</span><span class="special">:</span>
- <span class="keyword">explicit</span> <span class="identifier">fdoutbuf</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">);</span>
- <span class="comment">//...</span>
- <span class="special">};</span>
- <span class="keyword">class</span> <span class="identifier">fdostream</span>
- <span class="special">:</span> <span class="keyword">private</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">fdoutbuf</span><span class="special">></span>
- <span class="special">,</span> <span class="keyword">public</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span>
- <span class="special">{</span>
- <span class="comment">// Helper typedef's</span>
- <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">fdoutbuf</span><span class="special">></span> <span class="identifier">pbase_type</span><span class="special">;</span>
- <span class="keyword">typedef</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="identifier">base_type</span><span class="special">;</span>
- <span class="keyword">public</span><span class="special">:</span>
- <span class="keyword">explicit</span> <span class="identifier">fdostream</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">fd</span> <span class="special">)</span>
- <span class="special">:</span> <span class="identifier">pbase_type</span><span class="special">(</span> <span class="identifier">fd</span> <span class="special">),</span> <span class="identifier">base_type</span><span class="special">(</span> <span class="special">&</span><span class="identifier">member</span> <span class="special">){}</span>
- <span class="comment">//...</span>
- <span class="special">};</span>
- </pre>
- <p>
- The base-from-member idiom is an implementation detail, so it should not be
- visible to the clients (or any derived classes) of <code class="computeroutput"><span class="identifier">fdostream</span></code>.
- Due to the initialization order, the <code class="computeroutput"><span class="identifier">fdoutbuf</span></code>
- sub-object will get initialized before the <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span></code>
- sub-object does, making the former sub-object safe to use in the latter sub-object's
- construction. Since the <code class="computeroutput"><span class="identifier">fdoutbuf</span></code>
- sub-object of the final type is the only sub-object with the name <code class="computeroutput"><span class="identifier">member</span></code> that name can be used unqualified
- within the final class.
- </p>
- </div>
- <div class="section">
- <div class="titlepage"><div><div><h2 class="title" style="clear: both">
- <a name="base_from_member.example"></a><a class="link" href="base_from_member.html#base_from_member.example" title="Example">Example</a>
- </h2></div></div></div>
- <p>
- The base-from-member class templates should commonly involve only one base-from-member
- sub-object, usually for attaching a stream-buffer to an I/O stream. The next
- example demonstrates how to use multiple base-from-member sub-objects and the
- resulting qualification issues.
- </p>
- <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">utility</span><span class="special">/</span><span class="identifier">base_from_member</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
- <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">cstddef</span><span class="special">></span> <span class="comment">/* for NULL */</span>
- <span class="keyword">struct</span> <span class="identifier">an_int</span>
- <span class="special">{</span>
- <span class="keyword">int</span> <span class="identifier">y</span><span class="special">;</span>
- <span class="identifier">an_int</span><span class="special">(</span> <span class="keyword">float</span> <span class="identifier">yf</span> <span class="special">);</span>
- <span class="special">};</span>
- <span class="keyword">class</span> <span class="identifier">switcher</span>
- <span class="special">{</span>
- <span class="keyword">public</span><span class="special">:</span>
- <span class="identifier">switcher</span><span class="special">();</span>
- <span class="identifier">switcher</span><span class="special">(</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">int</span> <span class="special">*</span> <span class="special">);</span>
- <span class="comment">//...</span>
- <span class="special">};</span>
- <span class="keyword">class</span> <span class="identifier">flow_regulator</span>
- <span class="special">{</span>
- <span class="keyword">public</span><span class="special">:</span>
- <span class="identifier">flow_regulator</span><span class="special">(</span> <span class="identifier">switcher</span> <span class="special">&,</span> <span class="identifier">switcher</span> <span class="special">&</span> <span class="special">);</span>
- <span class="comment">//...</span>
- <span class="special">};</span>
- <span class="keyword">template</span> <span class="special"><</span> <span class="keyword">unsigned</span> <span class="identifier">Size</span> <span class="special">></span>
- <span class="keyword">class</span> <span class="identifier">fan</span>
- <span class="special">{</span>
- <span class="keyword">public</span><span class="special">:</span>
- <span class="keyword">explicit</span> <span class="identifier">fan</span><span class="special">(</span> <span class="identifier">switcher</span> <span class="special">);</span>
- <span class="comment">//...</span>
- <span class="special">};</span>
- <span class="keyword">class</span> <span class="identifier">system</span>
- <span class="special">:</span> <span class="keyword">private</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">an_int</span><span class="special">></span>
- <span class="special">,</span> <span class="keyword">private</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">switcher</span><span class="special">></span>
- <span class="special">,</span> <span class="keyword">private</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">switcher</span><span class="special">,</span> <span class="number">1</span><span class="special">></span>
- <span class="special">,</span> <span class="keyword">private</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">switcher</span><span class="special">,</span> <span class="number">2</span><span class="special">></span>
- <span class="special">,</span> <span class="keyword">protected</span> <span class="identifier">flow_regulator</span>
- <span class="special">,</span> <span class="keyword">public</span> <span class="identifier">fan</span><span class="special"><</span><span class="number">6</span><span class="special">></span>
- <span class="special">{</span>
- <span class="comment">// Helper typedef's</span>
- <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">an_int</span><span class="special">></span> <span class="identifier">pbase0_type</span><span class="special">;</span>
- <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">switcher</span><span class="special">></span> <span class="identifier">pbase1_type</span><span class="special">;</span>
- <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">switcher</span><span class="special">,</span> <span class="number">1</span><span class="special">></span> <span class="identifier">pbase2_type</span><span class="special">;</span>
- <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span><span class="identifier">switcher</span><span class="special">,</span> <span class="number">2</span><span class="special">></span> <span class="identifier">pbase3_type</span><span class="special">;</span>
- <span class="keyword">typedef</span> <span class="identifier">flow_regulator</span> <span class="identifier">base1_type</span><span class="special">;</span>
- <span class="keyword">typedef</span> <span class="identifier">fan</span><span class="special"><</span><span class="number">6</span><span class="special">></span> <span class="identifier">base2_type</span><span class="special">;</span>
- <span class="keyword">public</span><span class="special">:</span>
- <span class="identifier">system</span><span class="special">(</span> <span class="keyword">double</span> <span class="identifier">x</span> <span class="special">);</span>
- <span class="comment">//...</span>
- <span class="special">};</span>
- <span class="identifier">system</span><span class="special">::</span><span class="identifier">system</span><span class="special">(</span> <span class="keyword">double</span> <span class="identifier">x</span> <span class="special">)</span>
- <span class="special">:</span> <span class="identifier">pbase0_type</span><span class="special">(</span> <span class="number">0.2</span> <span class="special">)</span>
- <span class="special">,</span> <span class="identifier">pbase1_type</span><span class="special">()</span>
- <span class="special">,</span> <span class="identifier">pbase2_type</span><span class="special">(</span> <span class="special">-</span><span class="number">16</span><span class="special">,</span> <span class="special">&</span><span class="keyword">this</span><span class="special">-></span><span class="identifier">pbase0_type</span><span class="special">::</span><span class="identifier">member</span><span class="special">.</span><span class="identifier">y</span> <span class="special">)</span>
- <span class="special">,</span> <span class="identifier">pbase3_type</span><span class="special">(</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">static_cast</span><span class="special"><</span><span class="keyword">int</span> <span class="special">*>(</span><span class="identifier">NULL</span><span class="special">)</span> <span class="special">)</span>
- <span class="special">,</span> <span class="identifier">base1_type</span><span class="special">(</span> <span class="identifier">pbase3_type</span><span class="special">::</span><span class="identifier">member</span><span class="special">,</span> <span class="identifier">pbase1_type</span><span class="special">::</span><span class="identifier">member</span> <span class="special">)</span>
- <span class="special">,</span> <span class="identifier">base2_type</span><span class="special">(</span> <span class="identifier">pbase2_type</span><span class="special">::</span><span class="identifier">member</span> <span class="special">)</span>
- <span class="special">{</span>
- <span class="comment">//...</span>
- <span class="special">}</span>
- </pre>
- <p>
- The final class has multiple sub-objects with the name <code class="computeroutput"><span class="identifier">member</span></code>,
- so any use of that name needs qualification by a name of the appropriate base
- type. (Using <code class="computeroutput"><span class="keyword">typedef</span></code>s ease mentioning
- the base types.) However, the fix introduces a new problem when a pointer is
- needed. Using the address operator with a sub-object qualified with its class's
- name results in a pointer-to-member (here, having a type of <code class="computeroutput"><span class="identifier">an_int</span>
- <span class="identifier">boost</span><span class="special">::</span><span class="identifier">base_from_member</span><span class="special"><</span>
- <span class="identifier">an_int</span><span class="special">,</span>
- <span class="number">0</span><span class="special">></span> <span class="special">::</span> <span class="special">*</span></code>) instead
- of a pointer to the member (having a type of <code class="computeroutput"><span class="identifier">an_int</span>
- <span class="special">*</span></code>). The new problem is fixed by qualifying
- the sub-object with <code class="computeroutput"><span class="keyword">this</span><span class="special">-></span></code>
- and is needed just for pointers, and not for references or values.
- </p>
- <p>
- There are some argument conversions in the initialization. The constructor
- argument for <code class="computeroutput"><span class="identifier">pbase0_type</span></code> is
- converted from <code class="computeroutput"><span class="keyword">double</span></code> to <code class="computeroutput"><span class="keyword">float</span></code>. The first constructor argument for <code class="computeroutput"><span class="identifier">pbase2_type</span></code> is converted from <code class="computeroutput"><span class="keyword">int</span></code> to <code class="computeroutput"><span class="keyword">double</span></code>.
- The second constructor argument for <code class="computeroutput"><span class="identifier">pbase3_type</span></code>
- is a special case of necessary conversion; all forms of the null-pointer literal
- in C++ (except <code class="computeroutput"><span class="keyword">nullptr</span></code> from C++11)
- also look like compile-time integral expressions, so C++ always interprets
- such code as an integer when it has overloads that can take either an integer
- or a pointer. The last conversion is necessary for the compiler to call a constructor
- form with the exact pointer type used in <code class="computeroutput"><span class="identifier">switcher</span></code>'s
- constructor. (If C++11's <code class="computeroutput"><span class="keyword">nullptr</span></code>
- is used, it still needs a conversion if multiple pointer types can be accepted
- in a constructor call but <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">nullptr_t</span></code>
- cannot.)
- </p>
- </div>
- <div class="section">
- <div class="titlepage"><div><div><h2 class="title" style="clear: both">
- <a name="base_from_member.acknowledgments"></a><a class="link" href="base_from_member.html#base_from_member.acknowledgments" title="Acknowledgments">Acknowledgments</a>
- </h2></div></div></div>
- <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
- <li class="listitem">
- <a href="http://www.boost.org/people/ed_brey.htm" target="_top">Ed Brey</a> suggested
- some interface changes.
- </li>
- <li class="listitem">
- <a href="http://www.moocat.org" target="_top">R. Samuel Klatchko</a> (<a href="mailto:rsk%40moocat.org" target="_top">rsk@moocat.org</a>,
- <a href="mailto:rsk%40brightmail.com" target="_top">rsk@brightmail.com</a>) invented
- the idiom of how to use a class member for initializing a base class.
- </li>
- <li class="listitem">
- <a href="http://www.boost.org/people/dietmar_kuehl.htm" target="_top">Dietmar Kuehl</a>
- popularized the base-from-member idiom in his <a href="http://www.informatik.uni-konstanz.de/~kuehl/c++/iostream/" target="_top">IOStream
- example classes</a>.
- </li>
- <li class="listitem">
- Jonathan Turkanis supplied an implementation of generating the constructor
- templates that can be controlled and automated with macros. The implementation
- uses the <a href="../../../preprocessor/index.html" target="_top">Preprocessor library</a>.
- </li>
- <li class="listitem">
- <a href="http://www.boost.org/people/daryle_walker.html%22%3eDaryle" target="_top">Walker</a>
- started the library. Contributed the test file <a href="../../test/base_from_member_test.cpp" target="_top">base_from_member_test.cpp</a>.
- </li>
- </ul></div>
- </div>
- </div>
- <table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
- <td align="left"><p><small>Last revised: December 10, 2019 at 00:21:47 GMT</small></p></td>
- <td align="right"><div class="copyright-footer"></div></td>
- </tr></table>
- <hr>
- <div class="spirit-nav"></div>
- </body>
- </html>
|