Files
callable_traits/doc/html/callable_traits_interface_example.html
2016-05-15 18:29:38 -05:00

957 lines
146 KiB
HTML

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Example: Java-style interfaces without inheritance</title>
<link rel="stylesheet" href="boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="index.html" title="CallableTraits">
<link rel="up" href="index.html" title="CallableTraits">
<link rel="prev" href="callable_traits/example_std_function_sugar.html" title="Example: std::function sugar">
<link rel="next" href="callable_traits/contact.html" title="Contact">
</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">
<a accesskey="p" href="callable_traits/example_std_function_sugar.html"><img src="../src/images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="../src/images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="../src/images/home.png" alt="Home"></a><a accesskey="n" href="callable_traits/contact.html"><img src="../src/images/next.png" alt="Next"></a>
</div>
<div lang="en" class="article">
<div class="titlepage">
<div>
<div><h2 class="title">
<a name="callable_traits_interface_example"></a>Example: Java-style interfaces without inheritance</h2></div>
<div><div class="authorgroup">
<div class="author"><h3 class="author">
<span class="firstname">Barrett</span> <span class="surname">Adair</span>
</h3></div>
<div class="author"><h3 class="author">
<span class="firstname">Tobias</span> <span class="surname">Schwinger</span>
</h3></div>
</div></div>
<div><p class="copyright">Copyright &#169; 2016 (Modified Work) Barrett Adair</p></div>
<div><p class="copyright">Copyright &#169; 2007 Tobias Schwinger</p></div>
<div><div class="legalnotice">
<a name="callable_traits_interface_example.legal"></a><p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE.md 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>
<h3>
<a name="callable_traits_interface_example.h0"></a>
<span class="phrase"><a name="callable_traits_interface_example.explanation"></a></span><a class="link" href="callable_traits_interface_example.html#callable_traits_interface_example.explanation">Explanation</a>
</h3>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
This example is based on the <a href="http://www.boost.org/doc/libs/1_60_0/libs/function_types/example/interface.hpp" target="_top">Boost.FunctionTypes
interface example.</a>
</p></td></tr>
</table></div>
<p>
An interface is a collection of member function prototypes that may be implemented
by classes. Objects of classes that implement the interface can then be assigned
to an interface variable through which the interface's functions can be called.
</p>
<p>
Interfaces are a <a href="https://en.wikipedia.org/wiki/Interface_(Java)" target="_top">feature
of the Java programming language</a>. The most obvious way to model an
interface in C++ is to define a pure abstract base class. However, the inheritance
approach is neither the most efficient, nor the most flexible solution. Inheritance-based
interfaces have the following drawbacks:
</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
All functions must be virtual
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
a function that calls another function of the interface must do so
via virtual dispatch (as opposed to inlining)
</li>
<li class="listitem">
a class can not implement an interface's (overloaded) function via
a function template
</li>
</ul></div>
</li>
<li class="listitem">
Inheritance is intrusive
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
object size increases
</li>
<li class="listitem">
clients are always polymorphic
</li>
<li class="listitem">
dependencies cause tighter coupling
</li>
</ul></div>
</li>
</ol></div>
<p>
Fortunately, it is possible to eliminate all the drawbacks mentioned above
based on an alternative implementation using template metaprogramming, preprocessor
metaprogramming, and type erasure techniques. In this example, we will use
<code class="computeroutput"><span class="identifier">CallableTraits</span></code> and the <a href="http://www.boost.org/doc/libs/1_60_0/libs/preprocessor/doc/index.html" target="_top">Boost.Preprocessor
library</a> to create a macro which is used to define Java-style interfaces
<span class="bold"><strong>that can be retroactively applied to any object, with
no performance lost versus inheritance polymorphism</strong></span>. The macro is
used like this:
</p>
<pre class="programlisting"><span class="identifier">DEFINE_INTERFACE</span><span class="special">(</span> <span class="identifier">interface_x</span><span class="special">,</span>
<span class="special">((</span> <span class="identifier">a_func</span><span class="special">,</span> <span class="keyword">void</span><span class="special">(</span><span class="keyword">int</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">))</span>
<span class="special">((</span> <span class="identifier">a_func</span><span class="special">,</span> <span class="keyword">void</span><span class="special">(</span><span class="keyword">long</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">))</span>
<span class="special">((</span> <span class="identifier">another_func</span><span class="special">,</span> <span class="keyword">int</span><span class="special">()</span> <span class="special">))</span>
<span class="special">);</span>
</pre>
<p>
This loosely corresponds to the following Java code:
</p>
<pre class="programlisting"><span class="keyword">public</span> <span class="identifier">interface</span> <span class="identifier">interface_x</span> <span class="special">{</span>
<span class="keyword">void</span> <span class="identifier">a_func</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">x</span><span class="special">);</span>
<span class="keyword">void</span> <span class="identifier">a_func</span><span class="special">(</span><span class="keyword">long</span> <span class="identifier">x</span><span class="special">);</span>
<span class="keyword">int</span> <span class="identifier">another_func</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
The <code class="computeroutput"><span class="identifier">DEFINE_INTERFACE</span></code> macro
is applied to object instances, rather than class definitions. This allows
the interfacing of objects whose definitions are not accessible to the programmer.
All constraints are still checked at compile time. This example implementation
even accounts for member data, such as <code class="computeroutput"><span class="identifier">some_data</span></code>
below:
</p>
<pre class="programlisting"><span class="identifier">DEFINE_INTERFACE</span><span class="special">(</span> <span class="identifier">interface_y</span><span class="special">,</span>
<span class="special">((</span> <span class="identifier">a_func</span><span class="special">,</span> <span class="keyword">void</span><span class="special">(</span><span class="keyword">int</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">))</span>
<span class="special">((</span> <span class="identifier">some_data</span><span class="special">,</span> <span class="keyword">int</span> <span class="special">))</span>
<span class="special">);</span>
</pre>
<p>
A more fleshed-out implementation of this would be very useful to anyone using
OOP design patterns in C++, or to developers of generic APIs. Arguably, the
<code class="computeroutput"><span class="identifier">DEFINE_INTERFACE</span></code> macro is easier
than writing pure abstract base classes. However, this implementation is not
without drawbacks. To name a few:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
This example implementation lacks features for memory management and move
semantics
</li>
<li class="listitem">
No custom error messages
</li>
<li class="listitem">
No comparison operators are overloaded
</li>
<li class="listitem">
Suboptimal compile-time performance
</li>
<li class="listitem">
Inherited members cannot be used to implement the interface
</li>
<li class="listitem">
This example implementation has not been thoroughly tested
</li>
<li class="listitem">
This example does not build in on the following platforms:
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; ">
<li class="listitem">
MSVC
</li>
<li class="listitem">
GCC &lt; 4.9.2
</li>
<li class="listitem">
Clang &lt; 3.7
</li>
</ul></div>
</li>
</ul></div>
<h3>
<a name="callable_traits_interface_example.h1"></a>
<span class="phrase"><a name="callable_traits_interface_example.usage"></a></span><a class="link" href="callable_traits_interface_example.html#callable_traits_interface_example.usage">Usage</a>
</h3>
<p>
This short program shows how to use the example <code class="computeroutput"><span class="identifier">DEFINE_INTERFACE</span></code>
macro. The implementation can be found in the following section.
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">iostream</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="string">"interface.hpp"</span>
<span class="identifier">DEFINE_INTERFACE</span><span class="special">(</span><span class="identifier">interface_x</span><span class="special">,</span>
<span class="special">((</span> <span class="identifier">a_func</span><span class="special">,</span> <span class="keyword">void</span><span class="special">(</span><span class="keyword">int</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">))</span>
<span class="special">((</span> <span class="identifier">a_func</span><span class="special">,</span> <span class="keyword">void</span><span class="special">(</span><span class="keyword">long</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">))</span>
<span class="special">((</span> <span class="identifier">another_func</span><span class="special">,</span> <span class="keyword">int</span><span class="special">()</span> <span class="special">))</span>
<span class="special">((</span> <span class="identifier">some_data</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="special">))</span>
<span class="special">);</span>
<span class="comment">// two classes that implement interface_x</span>
<span class="keyword">struct</span> <span class="identifier">a_class</span> <span class="special">{</span>
<span class="keyword">void</span> <span class="identifier">a_func</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">v</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"a_class::void a_func(int v = "</span> <span class="special">&lt;&lt;</span> <span class="identifier">v</span> <span class="special">&lt;&lt;</span> <span class="string">")"</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">a_func</span><span class="special">(</span><span class="keyword">long</span> <span class="identifier">v</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"a_class::void a_func(long v = "</span> <span class="special">&lt;&lt;</span> <span class="identifier">v</span> <span class="special">&lt;&lt;</span> <span class="string">")"</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">int</span> <span class="identifier">another_func</span><span class="special">()</span> <span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"a_class::another_func() = 3"</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="keyword">return</span> <span class="number">3</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">some_data</span> <span class="special">=</span> <span class="string">"a_class's data"</span><span class="special">;</span>
<span class="special">};</span>
<span class="keyword">struct</span> <span class="identifier">another_class</span> <span class="special">{</span>
<span class="comment">// Notice a_func is implemented as a function template? No problem for our interface.</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">void</span> <span class="identifier">a_func</span><span class="special">(</span><span class="identifier">T</span> <span class="identifier">v</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span>
<span class="string">"another_class::void a_func(T v = "</span> <span class="special">&lt;&lt;</span> <span class="identifier">v</span> <span class="special">&lt;&lt;</span> <span class="string">")"</span>
<span class="string">" [ T = "</span> <span class="special">&lt;&lt;</span> <span class="keyword">typeid</span><span class="special">(</span><span class="identifier">T</span><span class="special">).</span><span class="identifier">name</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">" ]"</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">int</span> <span class="identifier">another_func</span><span class="special">()</span> <span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"another_class::another_func() = 5"</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="keyword">return</span> <span class="number">5</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">some_data</span> <span class="special">=</span> <span class="string">"another_class's data"</span><span class="special">;</span>
<span class="special">};</span>
<span class="keyword">void</span> <span class="identifier">print_data</span><span class="special">(</span><span class="identifier">interface_x</span> <span class="identifier">obj</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="identifier">obj</span><span class="special">.</span><span class="identifier">some_data</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="comment">// Both classes above can be assigned to the interface variable and their</span>
<span class="comment">// member functions can be called through it.</span>
<span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> <span class="special">{</span>
<span class="identifier">a_class</span> <span class="identifier">x</span><span class="special">;</span>
<span class="identifier">another_class</span> <span class="identifier">y</span><span class="special">;</span>
<span class="identifier">interface_x</span> <span class="identifier">i</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span>
<span class="identifier">i</span><span class="special">.</span><span class="identifier">a_func</span><span class="special">(</span><span class="number">12</span><span class="special">);</span>
<span class="identifier">i</span><span class="special">.</span><span class="identifier">a_func</span><span class="special">(</span><span class="number">77L</span><span class="special">);</span>
<span class="identifier">i</span><span class="special">.</span><span class="identifier">another_func</span><span class="special">();</span>
<span class="identifier">print_data</span><span class="special">(</span><span class="identifier">i</span><span class="special">);</span>
<span class="identifier">i</span><span class="special">.</span><span class="identifier">some_data</span><span class="special">()</span> <span class="special">=</span> <span class="string">"x's data has changed."</span><span class="special">;</span>
<span class="identifier">print_data</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span>
<span class="comment">//reusing the same interface object</span>
<span class="identifier">i</span> <span class="special">=</span> <span class="identifier">y</span><span class="special">;</span>
<span class="identifier">i</span><span class="special">.</span><span class="identifier">a_func</span><span class="special">(</span><span class="number">13</span><span class="special">);</span>
<span class="identifier">i</span><span class="special">.</span><span class="identifier">a_func</span><span class="special">(</span><span class="number">21L</span><span class="special">);</span>
<span class="identifier">i</span><span class="special">.</span><span class="identifier">another_func</span><span class="special">();</span>
<span class="identifier">print_data</span><span class="special">(</span><span class="identifier">y</span><span class="special">);</span>
<span class="special">}</span>
</pre>
<h3>
<a name="callable_traits_interface_example.h2"></a>
<span class="phrase"><a name="callable_traits_interface_example.implementation"></a></span><a class="link" href="callable_traits_interface_example.html#callable_traits_interface_example.implementation">Implementation</a>
</h3>
<p>
If you are unfamiliar with type erasure techniques, you may want to go learn
about them before reading the implementation header.
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">arg_at</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">result_of</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">pop_front</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">push_front</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">expand_args</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">replace_args</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">function_type</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">set_qualifiers</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">qualifier_flags</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">copy_qualifiers</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">is_like_function</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">remove_member_cv</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">get_qualifier_flags</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">apply_member_pointer</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">remove_member_pointer</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">remove_member_reference</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">qualified_parent_class_of</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">callable_traits</span><span class="special">/</span><span class="identifier">get_member_qualifier_flags</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">seq</span><span class="special">/</span><span class="identifier">seq</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">seq</span><span class="special">/</span><span class="identifier">elem</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">seq</span><span class="special">/</span><span class="identifier">size</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">tuple</span><span class="special">/</span><span class="identifier">elem</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">facilities</span><span class="special">/</span><span class="identifier">empty</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">repetition</span><span class="special">/</span><span class="identifier">repeat</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">preprocessor</span><span class="special">/</span><span class="identifier">punctuation</span><span class="special">/</span><span class="identifier">comma_if</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">utility</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">type_traits</span><span class="special">&gt;</span>
<span class="keyword">namespace</span> <span class="identifier">intrfc</span> <span class="special">{</span>
<span class="keyword">namespace</span> <span class="identifier">ct</span> <span class="special">=</span> <span class="identifier">callable_traits</span><span class="special">;</span>
<span class="comment">//this is our placeholder parent class for member pointers</span>
<span class="keyword">struct</span> <span class="identifier">secret</span> <span class="special">{};</span>
<span class="comment">// used to forward a parameter without copying it</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">using</span> <span class="identifier">forward_t</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">conditional_t</span><span class="special">&lt;</span> <span class="keyword">sizeof</span><span class="special">(</span><span class="keyword">void</span><span class="special">*)</span> <span class="special">&lt;</span> <span class="keyword">sizeof</span><span class="special">(</span><span class="identifier">T</span><span class="special">)</span>
<span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">add_lvalue_reference_t</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">add_const_t</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span> <span class="special">&gt;,</span> <span class="identifier">T</span><span class="special">&gt;;</span>
<span class="comment">// The member struct erases the object reference type that is supplied by</span>
<span class="comment">// function_type, which aliases an INVOKE-aware function type when</span>
<span class="comment">// a pmf is passed to it. We replace the first argument (which is</span>
<span class="comment">// a reference to an object of the member ptr's parent class, as required</span>
<span class="comment">// by INVOKE) with void*.</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Ptr</span><span class="special">,</span> <span class="identifier">Ptr</span> <span class="identifier">Value</span><span class="special">,</span> <span class="keyword">bool</span> <span class="identifier">IsPmf</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_member_function_pointer</span><span class="special">&lt;</span><span class="identifier">Ptr</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">member</span><span class="special">;</span>
<span class="comment">// this is our type erasure "glue". member&lt;...&gt;::wrapper::wrap is a static member function which</span>
<span class="comment">// casts a void* back to its original object type, and invokes the appropriate member. This first</span>
<span class="comment">// definition handles member functions.</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Pmf</span><span class="special">,</span> <span class="identifier">Pmf</span> <span class="identifier">PmfValue</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">member</span><span class="special">&lt;</span><span class="identifier">Pmf</span><span class="special">,</span> <span class="identifier">PmfValue</span><span class="special">,</span> <span class="keyword">true</span><span class="special">&gt;</span> <span class="special">{</span>
<span class="comment">// qualified_parent_class_of yields a reference type which is qualified</span>
<span class="comment">// according to the member function type.</span>
<span class="keyword">using</span> <span class="identifier">context</span> <span class="special">=</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">qualified_parent_class_of</span><span class="special">&lt;</span><span class="identifier">Pmf</span><span class="special">&gt;&gt;;</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span><span class="special">...</span> <span class="identifier">Args</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">member_wrapper</span> <span class="special">{</span>
<span class="keyword">static</span> <span class="keyword">inline</span> <span class="keyword">decltype</span><span class="special">(</span><span class="keyword">auto</span><span class="special">)</span>
<span class="identifier">wrap</span><span class="special">(</span><span class="keyword">void</span><span class="special">*</span> <span class="identifier">c</span><span class="special">,</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">forward_t</span><span class="special">&lt;</span><span class="identifier">Args</span><span class="special">&gt;...</span> <span class="identifier">args</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="special">(</span><span class="keyword">reinterpret_cast</span><span class="special">&lt;</span><span class="identifier">context</span><span class="special">*&gt;(</span><span class="identifier">c</span><span class="special">)-&gt;*</span><span class="identifier">PmfValue</span><span class="special">)(</span><span class="identifier">args</span><span class="special">...);</span>
<span class="special">};</span>
<span class="special">};</span>
<span class="comment">// removing the member pointer so that expand_args below doesn't include</span>
<span class="comment">// the INVOKE-required object argument</span>
<span class="keyword">using</span> <span class="identifier">abominable_function_type</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">remove_member_pointer</span><span class="special">&lt;</span><span class="identifier">Pmf</span><span class="special">&gt;;</span>
<span class="comment">// expand_args is used to expand the argument types into member_wrapper</span>
<span class="keyword">using</span> <span class="identifier">wrapper</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">expand_args</span><span class="special">&lt;</span>
<span class="identifier">abominable_function_type</span><span class="special">,</span> <span class="identifier">member_wrapper</span><span class="special">&gt;;</span>
<span class="special">};</span>
<span class="comment">// This specialization handles member data.</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">C</span><span class="special">,</span> <span class="identifier">T</span> <span class="identifier">C</span><span class="special">::*</span> <span class="identifier">PmdValue</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">member</span><span class="special">&lt;</span><span class="identifier">T</span> <span class="identifier">C</span><span class="special">::*,</span> <span class="identifier">PmdValue</span><span class="special">,</span> <span class="keyword">false</span><span class="special">&gt;</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">no_ref</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;;</span>
<span class="keyword">static</span> <span class="keyword">constexpr</span> <span class="keyword">const</span> <span class="keyword">bool</span> <span class="identifier">is_const</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_const</span><span class="special">&lt;</span><span class="identifier">no_ref</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">context</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">conditional_t</span><span class="special">&lt;</span><span class="identifier">is_const</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">C</span><span class="special">,</span> <span class="identifier">C</span><span class="special">&gt;;</span>
<span class="keyword">struct</span> <span class="identifier">wrapper</span> <span class="special">{</span>
<span class="keyword">static</span> <span class="keyword">inline</span> <span class="identifier">T</span><span class="special">&amp;</span>
<span class="identifier">wrap</span><span class="special">(</span><span class="keyword">void</span><span class="special">*</span> <span class="identifier">c</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="keyword">reinterpret_cast</span><span class="special">&lt;</span><span class="identifier">context</span><span class="special">*&gt;(</span><span class="identifier">c</span><span class="special">)-&gt;*</span><span class="identifier">PmdValue</span><span class="special">;</span>
<span class="special">};</span>
<span class="special">};</span>
<span class="special">};</span>
<span class="special">}</span>
<span class="comment">// BOOST_PP_NIL is not defined - the code below is simply a large comment</span>
<span class="preprocessor">#ifdef</span> <span class="identifier">BOOST_PP_NIL</span>
<span class="identifier">DEFINE_INTERFACE</span><span class="special">(</span><span class="identifier">interface_x</span><span class="special">,</span>
<span class="special">((</span><span class="identifier">print_member_data</span><span class="special">,</span> <span class="keyword">void</span><span class="special">()</span> <span class="keyword">const</span><span class="special">))</span>
<span class="special">((</span><span class="identifier">member_data</span><span class="special">,</span> <span class="keyword">int</span><span class="special">))</span>
<span class="special">);</span>
<span class="comment">// The above macro invocation would expand to the following code (sans comments and formatting, of course):</span>
<span class="comment">// most of our implementation logic is dumped into this</span>
<span class="comment">// class to reduce the chance of naming conflicts. We could</span>
<span class="comment">// use a namespace instead, except that namespaces can't be</span>
<span class="comment">// opened inside class definition. Anywhere you see "interface_x",</span>
<span class="comment">// "print_member_data", and "member_data", remember that these</span>
<span class="comment">// names originate from the macro parameters.</span>
<span class="keyword">struct</span> <span class="identifier">interface_x_detail</span> <span class="special">{</span>
<span class="comment">// This will be our root base class, containing our vtable and void*</span>
<span class="comment">// necessary for type erasure.</span>
<span class="keyword">struct</span> <span class="identifier">interface_root</span> <span class="special">{</span>
<span class="keyword">struct</span> <span class="identifier">vtable</span> <span class="special">{</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">secret</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">member_info0</span> <span class="special">{</span>
<span class="comment">// this comes from the from the macro parameters</span>
<span class="keyword">using</span> <span class="identifier">member_type</span> <span class="special">=</span> <span class="keyword">void</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="comment">// this definition is only used for member data</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">U</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Member</span> <span class="special">=</span> <span class="identifier">member_type</span><span class="special">,</span>
<span class="keyword">bool</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">has_member_qualifiers</span><span class="special">&lt;</span><span class="identifier">member_type</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">member_info</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">result_type</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">add_lvalue_reference_t</span><span class="special">&lt;</span><span class="identifier">Member</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">ptr_type</span> <span class="special">=</span> <span class="identifier">Member</span> <span class="identifier">U</span><span class="special">::*;</span>
<span class="comment">// we will use these later to correctly re-construct our interface function</span>
<span class="keyword">using</span> <span class="identifier">qualifiers</span> <span class="special">=</span>
<span class="keyword">decltype</span><span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">get_qualifier_flags</span><span class="special">&lt;</span><span class="identifier">Member</span><span class="special">&gt;());</span>
<span class="comment">// Our type erasure scheme will use a function to dereference</span>
<span class="comment">// pointers to member data</span>
<span class="keyword">using</span> <span class="identifier">type_erased_ptr</span> <span class="special">=</span> <span class="identifier">result_type</span><span class="special">(*)(</span><span class="keyword">void</span> <span class="special">*);</span>
<span class="special">};</span>
<span class="comment">// this specialization is only used for member functions</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">U</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">member_info</span><span class="special">&lt;</span><span class="identifier">U</span><span class="special">,</span> <span class="identifier">member_type</span><span class="special">,</span> <span class="keyword">true</span><span class="special">&gt;</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">ptr_type</span> <span class="special">=</span> <span class="identifier">member_type</span> <span class="identifier">U</span><span class="special">::*;</span>
<span class="keyword">using</span> <span class="identifier">result_type</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">&lt;</span><span class="identifier">ptr_type</span><span class="special">&gt;;</span>
<span class="comment">// The first argument of this function type is a qualified U</span>
<span class="comment">// reference, because function_type is defined in terms of INVOKE</span>
<span class="keyword">using</span> <span class="identifier">function_type</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">function_type</span><span class="special">&lt;</span><span class="identifier">ptr_type</span><span class="special">&gt;;</span>
<span class="comment">// we will use these later to correctly re-construct our forwarding</span>
<span class="comment">// interface function</span>
<span class="keyword">using</span> <span class="identifier">qualifiers</span> <span class="special">=</span>
<span class="keyword">decltype</span><span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">get_member_qualifier_flags</span><span class="special">&lt;</span><span class="identifier">ptr_type</span><span class="special">&gt;());</span>
<span class="comment">// overwriting the first argument with void*, "erasing" the</span>
<span class="comment">// qualified U reference. We then make it a function pointer.</span>
<span class="keyword">using</span> <span class="identifier">type_erased_ptr</span> <span class="special">=</span>
<span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">replace_args</span><span class="special">&lt;</span><span class="number">0</span><span class="special">,</span> <span class="identifier">function_type</span><span class="special">,</span> <span class="keyword">void</span><span class="special">*&gt;</span> <span class="special">*;</span>
<span class="special">};</span>
<span class="comment">// these aliases simply make later code easier to follow</span>
<span class="keyword">using</span> <span class="identifier">info</span> <span class="special">=</span> <span class="identifier">member_info</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">ptr_type</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">info</span><span class="special">::</span><span class="identifier">ptr_type</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">result_type</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">info</span><span class="special">::</span><span class="identifier">result_type</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">type_erased_ptr</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">info</span><span class="special">::</span><span class="identifier">type_erased_ptr</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">qualifiers</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">info</span><span class="special">::</span><span class="identifier">qualifiers</span><span class="special">;</span>
<span class="special">};</span>
<span class="comment">// this alias saves us some typing later</span>
<span class="keyword">using</span> <span class="identifier">pmf0</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">member_info0</span><span class="special">&lt;&gt;::</span><span class="identifier">ptr_type</span><span class="special">;</span>
<span class="comment">// This is our vtable function pointer entry, which will be initialized</span>
<span class="comment">// at compile-time.</span>
<span class="keyword">typename</span> <span class="identifier">member_info0</span><span class="special">&lt;&gt;::</span><span class="identifier">type_erased_ptr</span> <span class="identifier">func0</span><span class="special">;</span>
<span class="comment">// repeating for additional members supplied by the macro</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">secret</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">member_info1</span> <span class="special">{</span>
<span class="comment">// this comes from the from the macro parameters</span>
<span class="keyword">using</span> <span class="identifier">member_type</span> <span class="special">=</span> <span class="keyword">int</span><span class="special">;</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">U</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Member</span> <span class="special">=</span> <span class="identifier">member_type</span><span class="special">,</span>
<span class="keyword">bool</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_like_function</span><span class="special">&lt;</span><span class="identifier">member_type</span><span class="special">&gt;()&gt;</span>
<span class="keyword">struct</span> <span class="identifier">member_info</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">result_type</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">add_lvalue_reference_t</span><span class="special">&lt;</span><span class="identifier">Member</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">ptr_type</span> <span class="special">=</span> <span class="identifier">Member</span> <span class="identifier">U</span><span class="special">::*;</span>
<span class="keyword">using</span> <span class="identifier">qualifiers</span> <span class="special">=</span>
<span class="keyword">decltype</span><span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">get_qualifier_flags</span><span class="special">&lt;</span><span class="identifier">Member</span><span class="special">&gt;());</span>
<span class="keyword">using</span> <span class="identifier">type_erased_ptr</span> <span class="special">=</span> <span class="identifier">result_type</span><span class="special">(*)(</span><span class="keyword">void</span> <span class="special">*);</span>
<span class="special">};</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">U</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">member_info</span><span class="special">&lt;</span><span class="identifier">U</span><span class="special">,</span> <span class="identifier">member_type</span><span class="special">,</span> <span class="keyword">true</span><span class="special">&gt;</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">ptr_type</span> <span class="special">=</span> <span class="identifier">member_type</span> <span class="identifier">U</span><span class="special">::*;</span>
<span class="keyword">using</span> <span class="identifier">result_type</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">&lt;</span><span class="identifier">ptr_type</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">function_type</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">function_type</span><span class="special">&lt;</span><span class="identifier">ptr_type</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">qualifiers</span> <span class="special">=</span>
<span class="keyword">decltype</span><span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">get_member_qualifier_flags</span><span class="special">&lt;</span><span class="identifier">ptr_type</span><span class="special">&gt;());</span>
<span class="keyword">using</span> <span class="identifier">type_erased_ptr</span> <span class="special">=</span>
<span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">replace_args</span><span class="special">&lt;</span><span class="number">0</span><span class="special">,</span> <span class="identifier">function_type</span><span class="special">,</span> <span class="keyword">void</span> <span class="special">*&gt;</span> <span class="special">*;</span>
<span class="special">};</span>
<span class="keyword">using</span> <span class="identifier">info</span> <span class="special">=</span> <span class="identifier">member_info</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">ptr_type</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">info</span><span class="special">::</span><span class="identifier">ptr_type</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">result_type</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">info</span><span class="special">::</span><span class="identifier">result_type</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">type_erased_ptr</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">info</span><span class="special">::</span><span class="identifier">type_erased_ptr</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">qualifiers</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">info</span><span class="special">::</span><span class="identifier">qualifiers</span><span class="special">;</span>
<span class="special">};</span>
<span class="keyword">using</span> <span class="identifier">pmf1</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">member_info1</span><span class="special">&lt;&gt;::</span><span class="identifier">ptr_type</span><span class="special">;</span>
<span class="keyword">typename</span> <span class="identifier">member_info1</span><span class="special">&lt;&gt;::</span><span class="identifier">type_erased_ptr</span> <span class="identifier">func1</span><span class="special">;</span>
<span class="special">};</span>
<span class="comment">//our two data members</span>
<span class="keyword">const</span> <span class="identifier">vtable</span> <span class="special">*</span><span class="identifier">ptr_vtable</span><span class="special">;</span>
<span class="keyword">void</span> <span class="special">*</span><span class="identifier">obj_ptr</span><span class="special">;</span>
<span class="comment">// conversion constructor that creates an interface from an arbitrary class</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">inline</span> <span class="identifier">interface_root</span><span class="special">(</span><span class="identifier">T</span> <span class="special">&amp;</span><span class="identifier">that</span><span class="special">)</span>
<span class="special">:</span> <span class="identifier">ptr_vtable</span><span class="special">(&amp;</span><span class="identifier">vtable_holder</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">val_vtable</span><span class="special">),</span>
<span class="identifier">obj_ptr</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">addressof</span><span class="special">(</span><span class="identifier">that</span><span class="special">))</span> <span class="special">{</span>
<span class="special">}</span>
<span class="comment">// This template is instantiated for every class from which this interface</span>
<span class="comment">// is constructed (see constructor above). This instantiation causes the</span>
<span class="comment">// compiler to emit an initialized vtable for this type (via aggregate</span>
<span class="comment">// assignment later in the code).</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">vtable_holder</span> <span class="special">{</span> <span class="keyword">static</span> <span class="keyword">const</span> <span class="identifier">vtable</span> <span class="identifier">val_vtable</span><span class="special">;</span> <span class="special">};</span>
<span class="special">};</span>
<span class="comment">// this definition will not be used, but is necessary for eager template instantiation</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">int</span> <span class="identifier">I</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Ignored</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">secret</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">base</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">type</span> <span class="special">=</span> <span class="identifier">Ignored</span><span class="special">;</span>
<span class="special">};</span>
<span class="comment">// We use get_next_base to chain together our base classes, starting with interface_root.</span>
<span class="comment">// The rest of the classes each contain an interface member.</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">int</span> <span class="identifier">I</span><span class="special">&gt;</span>
<span class="keyword">using</span> <span class="identifier">get_next_base</span> <span class="special">=</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">conditional_t</span><span class="special">&lt;</span><span class="identifier">I</span> <span class="special">==</span> <span class="number">0</span><span class="special">,</span> <span class="identifier">interface_root</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">base</span><span class="special">&lt;</span><span class="identifier">I</span> <span class="special">-</span> <span class="number">1</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">&gt;;</span>
<span class="comment">// base_impl0 defines the first member supplied by the macro, specializing on</span>
<span class="comment">// the qualifiers that exist on the supplied member. The appropriate "apply"</span>
<span class="comment">// specialization will serve as a base class for our interface.</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span><span class="special">...</span> <span class="identifier">Args</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">base_impl0</span> <span class="special">{</span>
<span class="keyword">template</span> <span class="special">&lt;</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">flags</span> <span class="identifier">QualifierFlags</span><span class="special">,</span>
<span class="keyword">typename</span> <span class="identifier">Base</span> <span class="special">=</span> <span class="identifier">get_next_base</span><span class="special">&lt;</span><span class="number">0</span><span class="special">&gt;&gt;</span>
<span class="keyword">struct</span> <span class="identifier">apply</span><span class="special">;</span>
<span class="comment">// for unqualified member functions/data</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Base</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">apply</span><span class="special">&lt;</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">default_</span><span class="special">,</span> <span class="identifier">Base</span><span class="special">&gt;</span> <span class="special">:</span> <span class="identifier">Base</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">Base</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">ptr_vtable</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">obj_ptr</span><span class="special">;</span>
<span class="keyword">inline</span> <span class="keyword">decltype</span><span class="special">(</span><span class="keyword">auto</span><span class="special">)</span>
<span class="identifier">print_member_data</span><span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">forward_t</span><span class="special">&lt;</span><span class="identifier">Args</span><span class="special">&gt;...</span> <span class="identifier">args</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">ptr_vtable</span><span class="special">-&gt;</span><span class="identifier">func0</span><span class="special">(</span><span class="identifier">obj_ptr</span><span class="special">,</span> <span class="identifier">args</span><span class="special">...);</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="comment">// for const-qualified member functions/data</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Base</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">apply</span><span class="special">&lt;::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">const_</span><span class="special">,</span> <span class="identifier">Base</span><span class="special">&gt;</span> <span class="special">:</span> <span class="identifier">Base</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">Base</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">ptr_vtable</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">obj_ptr</span><span class="special">;</span>
<span class="keyword">inline</span> <span class="keyword">decltype</span><span class="special">(</span><span class="keyword">auto</span><span class="special">)</span>
<span class="identifier">print_member_data</span><span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">forward_t</span><span class="special">&lt;</span><span class="identifier">Args</span><span class="special">&gt;...</span> <span class="identifier">args</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">ptr_vtable</span><span class="special">-&gt;</span><span class="identifier">func0</span><span class="special">(</span><span class="identifier">obj_ptr</span><span class="special">,</span> <span class="identifier">args</span><span class="special">...);</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="comment">// for volatile-qualified member functions/data</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Base</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">apply</span><span class="special">&lt;::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">volatile_</span><span class="special">,</span> <span class="identifier">Base</span><span class="special">&gt;</span> <span class="special">:</span> <span class="identifier">Base</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">Base</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">ptr_vtable</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">obj_ptr</span><span class="special">;</span>
<span class="keyword">inline</span> <span class="keyword">decltype</span><span class="special">(</span><span class="keyword">auto</span><span class="special">)</span>
<span class="identifier">print_member_data</span><span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">forward_t</span><span class="special">&lt;</span><span class="identifier">Args</span><span class="special">&gt;...</span> <span class="identifier">args</span><span class="special">)</span> <span class="keyword">volatile</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">ptr_vtable</span><span class="special">-&gt;</span><span class="identifier">func0</span><span class="special">(</span><span class="identifier">obj_ptr</span><span class="special">,</span> <span class="identifier">args</span><span class="special">...);</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="comment">// for const-volatile-qualified member functions/data</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Base</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">apply</span><span class="special">&lt;(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">const_</span> <span class="special">|</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">volatile_</span><span class="special">),</span> <span class="identifier">Base</span><span class="special">&gt;</span> <span class="special">:</span> <span class="identifier">Base</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">Base</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">ptr_vtable</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">obj_ptr</span><span class="special">;</span>
<span class="keyword">inline</span> <span class="keyword">decltype</span><span class="special">(</span><span class="keyword">auto</span><span class="special">)</span>
<span class="identifier">print_member_data</span><span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">forward_t</span><span class="special">&lt;</span><span class="identifier">Args</span><span class="special">&gt;...</span> <span class="identifier">args</span><span class="special">)</span> <span class="keyword">const</span> <span class="keyword">volatile</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">ptr_vtable</span><span class="special">-&gt;</span><span class="identifier">func0</span><span class="special">(</span><span class="identifier">obj_ptr</span><span class="special">,</span> <span class="identifier">args</span><span class="special">...);</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="special">};</span>
<span class="comment">// this specialization helps link the bases together</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Ignored</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">base</span><span class="special">&lt;</span><span class="number">0</span><span class="special">,</span> <span class="identifier">Ignored</span><span class="special">&gt;</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">function_type</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">function_type</span><span class="special">&lt;</span>
<span class="keyword">typename</span> <span class="identifier">interface_root</span><span class="special">::</span><span class="identifier">vtable</span><span class="special">::</span><span class="identifier">pmf0</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">impl</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">expand_args</span><span class="special">&lt;</span>
<span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">pop_front</span><span class="special">&lt;</span><span class="identifier">function_type</span><span class="special">&gt;,</span>
<span class="identifier">base_impl0</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">qualifiers</span> <span class="special">=</span>
<span class="keyword">typename</span> <span class="identifier">interface_root</span><span class="special">::</span><span class="identifier">vtable</span><span class="special">::</span><span class="identifier">member_info0</span><span class="special">&lt;&gt;::</span><span class="identifier">qualifiers</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">type</span> <span class="special">=</span> <span class="identifier">impl</span><span class="special">::</span><span class="keyword">template</span> <span class="identifier">apply</span><span class="special">&lt;</span><span class="identifier">qualifiers</span><span class="special">::</span><span class="identifier">value</span><span class="special">&gt;;</span>
<span class="special">};</span>
<span class="comment">// repeat for additional interface members</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span><span class="special">...</span> <span class="identifier">Args</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">base_impl1</span> <span class="special">{</span>
<span class="keyword">template</span> <span class="special">&lt;::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">flags</span> <span class="identifier">QualifierFlags</span><span class="special">,</span>
<span class="keyword">typename</span> <span class="identifier">Base</span> <span class="special">=</span> <span class="identifier">get_next_base</span><span class="special">&lt;</span><span class="number">1</span><span class="special">&gt;&gt;</span>
<span class="keyword">struct</span> <span class="identifier">apply</span><span class="special">;</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Base</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">apply</span><span class="special">&lt;::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">default_</span><span class="special">,</span> <span class="identifier">Base</span><span class="special">&gt;</span> <span class="special">:</span> <span class="identifier">Base</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">Base</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">ptr_vtable</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">obj_ptr</span><span class="special">;</span>
<span class="keyword">inline</span> <span class="keyword">decltype</span><span class="special">(</span><span class="keyword">auto</span><span class="special">)</span>
<span class="identifier">member_data</span><span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">forward_t</span><span class="special">&lt;</span><span class="identifier">Args</span><span class="special">&gt;...</span> <span class="identifier">args</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">ptr_vtable</span><span class="special">-&gt;</span><span class="identifier">func1</span><span class="special">(</span><span class="identifier">obj_ptr</span><span class="special">,</span> <span class="identifier">args</span><span class="special">...);</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Base</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">apply</span><span class="special">&lt;::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">const_</span><span class="special">,</span> <span class="identifier">Base</span><span class="special">&gt;</span> <span class="special">:</span> <span class="identifier">Base</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">Base</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">ptr_vtable</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">obj_ptr</span><span class="special">;</span>
<span class="keyword">inline</span> <span class="keyword">decltype</span><span class="special">(</span><span class="keyword">auto</span><span class="special">)</span>
<span class="identifier">member_data</span><span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">forward_t</span><span class="special">&lt;</span><span class="identifier">Args</span><span class="special">&gt;...</span> <span class="identifier">args</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">ptr_vtable</span><span class="special">-&gt;</span><span class="identifier">func1</span><span class="special">(</span><span class="identifier">obj_ptr</span><span class="special">,</span> <span class="identifier">args</span><span class="special">...);</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Base</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">apply</span><span class="special">&lt;::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">volatile_</span><span class="special">,</span> <span class="identifier">Base</span><span class="special">&gt;</span> <span class="special">:</span> <span class="identifier">Base</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">Base</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">ptr_vtable</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">obj_ptr</span><span class="special">;</span>
<span class="keyword">inline</span> <span class="keyword">decltype</span><span class="special">(</span><span class="keyword">auto</span><span class="special">)</span>
<span class="identifier">member_data</span><span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">forward_t</span><span class="special">&lt;</span><span class="identifier">Args</span><span class="special">&gt;...</span> <span class="identifier">args</span><span class="special">)</span> <span class="keyword">volatile</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">ptr_vtable</span><span class="special">-&gt;</span><span class="identifier">func1</span><span class="special">(</span><span class="identifier">obj_ptr</span><span class="special">,</span> <span class="identifier">args</span><span class="special">...);</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Base</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">apply</span><span class="special">&lt;(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">const_</span> <span class="special">|</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">volatile_</span><span class="special">),</span> <span class="identifier">Base</span><span class="special">&gt;</span> <span class="special">:</span> <span class="identifier">Base</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">Base</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">ptr_vtable</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">obj_ptr</span><span class="special">;</span>
<span class="keyword">inline</span> <span class="keyword">decltype</span><span class="special">(</span><span class="keyword">auto</span><span class="special">)</span>
<span class="identifier">member_data</span><span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">forward_t</span><span class="special">&lt;</span><span class="identifier">Args</span><span class="special">&gt;...</span> <span class="identifier">args</span><span class="special">)</span> <span class="keyword">const</span> <span class="keyword">volatile</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">ptr_vtable</span><span class="special">-&gt;</span><span class="identifier">func1</span><span class="special">(</span><span class="identifier">obj_ptr</span><span class="special">,</span> <span class="identifier">args</span><span class="special">...);</span>
<span class="special">}</span>
<span class="special">};</span>
<span class="special">};</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Ignored</span><span class="special">&gt;</span>
<span class="keyword">struct</span> <span class="identifier">base</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span> <span class="identifier">Ignored</span><span class="special">&gt;</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">function_type</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">function_type</span><span class="special">&lt;</span>
<span class="keyword">typename</span> <span class="identifier">interface_root</span><span class="special">::</span><span class="identifier">vtable</span><span class="special">::</span><span class="identifier">pmf1</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">impl</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">expand_args</span><span class="special">&lt;</span>
<span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">pop_front</span><span class="special">&lt;</span><span class="identifier">function_type</span><span class="special">&gt;,</span>
<span class="identifier">base_impl1</span><span class="special">&gt;;</span>
<span class="keyword">using</span> <span class="identifier">qualifiers</span> <span class="special">=</span>
<span class="keyword">typename</span> <span class="identifier">interface_root</span><span class="special">::</span><span class="identifier">vtable</span><span class="special">::</span><span class="identifier">member_info1</span><span class="special">&lt;&gt;::</span><span class="identifier">qualifiers</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">type</span> <span class="special">=</span> <span class="identifier">impl</span><span class="special">::</span><span class="keyword">template</span> <span class="identifier">apply</span><span class="special">&lt;</span><span class="identifier">qualifiers</span><span class="special">::</span><span class="identifier">value</span><span class="special">&gt;;</span>
<span class="special">};</span>
<span class="special">};</span>
<span class="comment">// this initializes the vtable at compile time for every class used to construct an</span>
<span class="comment">// interface_x object. Member functions and member data are both handled.</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="identifier">interface_x_detail</span><span class="special">::</span><span class="identifier">interface_root</span><span class="special">::</span><span class="identifier">vtable</span> <span class="keyword">const</span>
<span class="identifier">interface_x_detail</span><span class="special">::</span><span class="identifier">interface_root</span><span class="special">::</span><span class="identifier">vtable_holder</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">val_vtable</span> <span class="special">=</span> <span class="special">{</span>
<span class="special">&amp;::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">member</span><span class="special">&lt;</span>
<span class="keyword">typename</span> <span class="identifier">vtable</span><span class="special">::</span><span class="identifier">member_info0</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">ptr_type</span><span class="special">,</span>
<span class="special">&amp;</span><span class="identifier">T</span><span class="special">::</span><span class="identifier">print_member_data</span>
<span class="special">&gt;::</span><span class="identifier">wrapper</span><span class="special">::</span><span class="identifier">wrap</span><span class="special">,</span>
<span class="special">&amp;::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">member</span><span class="special">&lt;</span>
<span class="keyword">typename</span> <span class="identifier">vtable</span><span class="special">::</span><span class="identifier">member_info1</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">ptr_type</span><span class="special">,</span>
<span class="special">&amp;</span><span class="identifier">T</span><span class="special">::</span><span class="identifier">member_data</span>
<span class="special">&gt;::</span><span class="identifier">wrapper</span><span class="special">::</span><span class="identifier">wrap</span>
<span class="special">};</span>
<span class="comment">// We inherit the base for the last member, which inherits all</span>
<span class="comment">// the bases before it. This strategy keeps our runtime memory layout</span>
<span class="comment">// as small as possible, but unfortunately increases compile times.</span>
<span class="keyword">struct</span> <span class="identifier">interface_x</span> <span class="special">:</span> <span class="identifier">interface_x_detail</span><span class="special">::</span><span class="identifier">base</span><span class="special">&lt;</span><span class="number">2</span> <span class="special">-</span> <span class="number">1</span><span class="special">&gt;::</span><span class="identifier">type</span> <span class="special">{</span>
<span class="keyword">using</span> <span class="identifier">detail</span> <span class="special">=</span> <span class="identifier">interface_x_detail</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">base</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">detail</span><span class="special">::</span><span class="identifier">base</span><span class="special">&lt;</span><span class="number">2</span> <span class="special">-</span> <span class="number">1</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">;</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">enable_if_t</span><span class="special">&lt;</span>
<span class="special">!</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_base_of</span><span class="special">&lt;</span><span class="identifier">interface_root</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">decay_t</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;::</span><span class="identifier">value</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&gt;</span> <span class="special">=</span> <span class="number">0</span><span class="special">&gt;</span>
<span class="keyword">inline</span> <span class="identifier">interface_x</span><span class="special">(</span><span class="identifier">T</span> <span class="special">&amp;</span><span class="identifier">that</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">base</span><span class="special">(</span><span class="identifier">that</span><span class="special">)</span> <span class="special">{}</span>
<span class="keyword">inline</span> <span class="identifier">interface_x</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">interface_x</span> <span class="special">&amp;)</span> <span class="special">=</span> <span class="keyword">default</span><span class="special">;</span>
<span class="comment">// These using declarations assist with IDE code-completion</span>
<span class="keyword">using</span> <span class="identifier">detail</span><span class="special">::</span><span class="identifier">base</span><span class="special">&lt;</span><span class="number">0</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">::</span><span class="identifier">print_member_data</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">detail</span><span class="special">::</span><span class="identifier">base</span><span class="special">&lt;</span><span class="number">1</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">::</span><span class="identifier">member_data</span><span class="special">;</span>
<span class="special">};</span>
<span class="preprocessor">#endif</span>
<span class="comment">// the interface definition on the client's side</span>
<span class="preprocessor">#define</span> <span class="identifier">DEFINE_INTERFACE</span><span class="special">(</span><span class="identifier">name</span><span class="special">,</span><span class="identifier">def</span><span class="special">)</span> <span class="special">\</span>
<span class="keyword">struct</span> <span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">name</span><span class="special">,</span> <span class="identifier">_detail</span><span class="special">)</span> <span class="special">{</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">struct</span> <span class="identifier">interface_root</span> <span class="special">{</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">struct</span> <span class="identifier">vtable</span> <span class="special">{</span> <span class="special">\</span>
<span class="special">\</span>
<span class="identifier">CALLABLE_TRAITS_INTERFACE__MEMBERS</span><span class="special">(</span><span class="identifier">def</span><span class="special">,</span> <span class="identifier">VTABLE</span><span class="special">)</span> <span class="special">\</span>
<span class="special">};</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">const</span> <span class="identifier">vtable</span> <span class="special">*</span> <span class="identifier">ptr_vtable</span><span class="special">;</span> <span class="special">\</span>
<span class="keyword">void</span><span class="special">*</span> <span class="identifier">obj_ptr</span><span class="special">;</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="special">\</span>
<span class="keyword">inline</span> <span class="identifier">interface_root</span><span class="special">(</span><span class="identifier">T</span><span class="special">&amp;</span> <span class="identifier">that</span><span class="special">)</span> <span class="special">\</span>
<span class="special">:</span> <span class="identifier">ptr_vtable</span><span class="special">(&amp;</span><span class="identifier">vtable_holder</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">val_vtable</span><span class="special">),</span> <span class="special">\</span>
<span class="identifier">obj_ptr</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">addressof</span><span class="special">(</span><span class="identifier">that</span><span class="special">))</span> <span class="special">{}</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="special">\</span>
<span class="keyword">struct</span> <span class="identifier">vtable_holder</span> <span class="special">{</span> <span class="special">\</span>
<span class="keyword">static</span> <span class="keyword">const</span> <span class="identifier">vtable</span> <span class="identifier">val_vtable</span><span class="special">;</span> <span class="special">\</span>
<span class="special">};</span> <span class="special">\</span>
<span class="special">};</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">int</span> <span class="identifier">I</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Ignored</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">secret</span><span class="special">&gt;</span> <span class="special">\</span>
<span class="keyword">struct</span> <span class="identifier">base</span><span class="special">{</span> <span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">type</span> <span class="special">=</span> <span class="identifier">Ignored</span><span class="special">;</span> <span class="special">\</span>
<span class="special">};</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">int</span> <span class="identifier">I</span><span class="special">&gt;</span> <span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">get_next_base</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">conditional_t</span><span class="special">&lt;</span> <span class="special">\</span>
<span class="identifier">I</span> <span class="special">==</span> <span class="number">0</span><span class="special">,</span> <span class="identifier">interface_root</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">base</span><span class="special">&lt;</span><span class="identifier">I</span> <span class="special">-</span> <span class="number">1</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">&gt;;</span> <span class="special">\</span>
<span class="special">\</span>
<span class="identifier">CALLABLE_TRAITS_INTERFACE__MEMBERS</span><span class="special">(</span><span class="identifier">def</span><span class="special">,</span> <span class="identifier">BASES</span><span class="special">)</span> <span class="special">\</span>
<span class="special">};</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">&gt;</span> <span class="special">\</span>
<span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">name</span><span class="special">,</span> <span class="identifier">_detail</span><span class="special">)::</span><span class="identifier">interface_root</span><span class="special">::</span><span class="identifier">vtable</span> <span class="keyword">const</span> <span class="special">\</span>
<span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">name</span><span class="special">,</span> <span class="identifier">_detail</span><span class="special">)::</span><span class="identifier">interface_root</span><span class="special">::</span><span class="identifier">vtable_holder</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span> <span class="special">\</span>
<span class="special">::</span><span class="identifier">val_vtable</span> <span class="special">=</span> <span class="special">\</span>
<span class="special">{</span> <span class="identifier">CALLABLE_TRAITS_INTERFACE__MEMBERS</span><span class="special">(</span><span class="identifier">def</span><span class="special">,</span> <span class="identifier">INIT_VTABLE</span><span class="special">)</span> <span class="special">};</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">struct</span> <span class="identifier">name</span> <span class="special">:</span> <span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">name</span><span class="special">,</span> <span class="identifier">_detail</span><span class="special">)</span> <span class="special">\</span>
<span class="special">::</span><span class="identifier">base</span><span class="special">&lt;</span><span class="identifier">BOOST_PP_SEQ_SIZE</span><span class="special">(</span><span class="identifier">def</span><span class="special">)</span> <span class="special">-</span> <span class="number">1</span><span class="special">&gt;::</span><span class="identifier">type</span> <span class="special">{</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">detail</span> <span class="special">=</span> <span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">name</span><span class="special">,</span> <span class="identifier">_detail</span><span class="special">);</span> <span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">base</span> <span class="special">=</span> <span class="special">\</span>
<span class="keyword">typename</span> <span class="identifier">detail</span><span class="special">::</span><span class="identifier">base</span><span class="special">&lt;</span><span class="identifier">BOOST_PP_SEQ_SIZE</span><span class="special">(</span><span class="identifier">def</span><span class="special">)</span> <span class="special">-</span> <span class="number">1</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">;</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">enable_if_t</span><span class="special">&lt;</span> <span class="special">\</span>
<span class="special">!</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_base_of</span><span class="special">&lt;</span><span class="identifier">interface_root</span><span class="special">,</span> <span class="special">\</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">decay_t</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;::</span><span class="identifier">value</span><span class="special">,</span> <span class="keyword">int</span><span class="special">&gt;</span> <span class="special">=</span> <span class="number">0</span><span class="special">&gt;</span> <span class="special">\</span>
<span class="keyword">inline</span> <span class="identifier">name</span><span class="special">(</span><span class="identifier">T</span><span class="special">&amp;</span> <span class="identifier">that</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">base</span><span class="special">(</span><span class="identifier">that</span><span class="special">)</span> <span class="special">{}</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">inline</span> <span class="identifier">name</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">name</span> <span class="special">&amp;)</span> <span class="special">=</span> <span class="keyword">default</span><span class="special">;</span> <span class="special">\</span>
<span class="special">\</span>
<span class="identifier">CALLABLE_TRAITS_INTERFACE__MEMBERS</span><span class="special">(</span><span class="identifier">def</span><span class="special">,</span> <span class="identifier">USING_DECLARATIONS</span><span class="special">)</span> <span class="special">\</span>
<span class="special">}</span> <span class="special">\</span>
<span class="comment">/**/</span>
<span class="comment">// preprocessing code details</span>
<span class="comment">// iterate all of the interface's members and invoke a macro, prefixed</span>
<span class="comment">// with CALLABLE_TRAITS_INTERFACE__</span>
<span class="preprocessor">#define</span> <span class="identifier">CALLABLE_TRAITS_INTERFACE__MEMBERS</span><span class="special">(</span><span class="identifier">seq</span><span class="special">,</span><span class="identifier">macro</span><span class="special">)</span> <span class="special">\</span>
<span class="identifier">BOOST_PP_REPEAT</span><span class="special">(</span><span class="identifier">BOOST_PP_SEQ_SIZE</span><span class="special">(</span><span class="identifier">seq</span><span class="special">),</span> <span class="special">\</span>
<span class="identifier">CALLABLE_TRAITS_INTERFACE__</span> <span class="special">##</span> <span class="identifier">macro</span><span class="special">,</span> <span class="identifier">seq</span><span class="special">)</span> <span class="special">\</span>
<span class="comment">/**/</span>
<span class="comment">// generate the vtable initilizer code</span>
<span class="preprocessor">#define</span> <span class="identifier">CALLABLE_TRAITS_INTERFACE__INIT_VTABLE</span><span class="special">(</span><span class="identifier">z</span><span class="special">,</span><span class="identifier">i</span><span class="special">,</span><span class="identifier">seq</span><span class="special">)</span> <span class="special">\</span>
<span class="identifier">CALLABLE_TRAITS_INTERFACE__INIT_VTABLE_I</span><span class="special">(</span><span class="identifier">i</span><span class="special">,</span> <span class="special">\</span>
<span class="identifier">BOOST_PP_TUPLE_ELEM</span><span class="special">(</span><span class="number">2</span><span class="special">,</span><span class="number">0</span><span class="special">,</span><span class="identifier">BOOST_PP_SEQ_ELEM</span><span class="special">(</span><span class="identifier">i</span><span class="special">,</span><span class="identifier">seq</span><span class="special">)))</span> <span class="special">\</span>
<span class="comment">/**/</span>
<span class="preprocessor">#define</span> <span class="identifier">CALLABLE_TRAITS_INTERFACE__INIT_VTABLE_I</span><span class="special">(</span><span class="identifier">i</span><span class="special">,</span><span class="identifier">mem</span><span class="special">)</span> <span class="special">\</span>
<span class="identifier">BOOST_PP_COMMA_IF</span><span class="special">(</span><span class="identifier">i</span><span class="special">)</span> <span class="special">\</span>
<span class="special">&amp;::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">member</span><span class="special">&lt;</span> <span class="special">\</span>
<span class="keyword">typename</span> <span class="identifier">vtable</span><span class="special">::</span><span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">member_info</span><span class="special">,</span> <span class="identifier">i</span><span class="special">)&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">ptr_type</span><span class="special">,\</span>
<span class="special">&amp;</span><span class="identifier">T</span><span class="special">::</span><span class="identifier">mem</span> <span class="special">\</span>
<span class="special">&gt;::</span><span class="identifier">wrapper</span><span class="special">::</span><span class="identifier">wrap</span> <span class="special">\</span>
<span class="comment">/**/</span>
<span class="comment">//generate the vtable</span>
<span class="preprocessor">#define</span> <span class="identifier">CALLABLE_TRAITS_INTERFACE__VTABLE</span><span class="special">(</span><span class="identifier">z</span><span class="special">,</span><span class="identifier">i</span><span class="special">,</span><span class="identifier">seq</span><span class="special">)</span> <span class="special">\</span>
<span class="identifier">CALLABLE_TRAITS_INTERFACE__VTABLE_I</span><span class="special">(</span><span class="identifier">z</span><span class="special">,</span><span class="identifier">i</span><span class="special">,</span> <span class="special">\</span>
<span class="identifier">BOOST_PP_TUPLE_ELEM</span><span class="special">(</span><span class="number">2</span><span class="special">,</span><span class="number">1</span><span class="special">,</span><span class="identifier">BOOST_PP_SEQ_ELEM</span><span class="special">(</span><span class="identifier">i</span><span class="special">,</span><span class="identifier">seq</span><span class="special">)))</span> <span class="special">\</span>
<span class="comment">/**/</span>
<span class="preprocessor">#define</span> <span class="identifier">CALLABLE_TRAITS_INTERFACE__VTABLE_I</span><span class="special">(</span><span class="identifier">z</span><span class="special">,</span><span class="identifier">i</span><span class="special">,</span><span class="identifier">signature</span><span class="special">)</span> <span class="special">\</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">secret</span><span class="special">&gt;</span> <span class="special">\</span>
<span class="keyword">struct</span> <span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">member_info</span><span class="special">,</span> <span class="identifier">i</span><span class="special">)</span> <span class="special">{</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">member_type</span> <span class="special">=</span> <span class="identifier">signature</span><span class="special">;</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">U</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Member</span> <span class="special">=</span> <span class="identifier">member_type</span><span class="special">,</span> <span class="special">\</span>
<span class="keyword">bool</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">is_like_function</span><span class="special">&lt;</span><span class="identifier">member_type</span><span class="special">&gt;()&gt;</span> <span class="special">\</span>
<span class="keyword">struct</span> <span class="identifier">member_info</span> <span class="special">{</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">result_type</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">add_lvalue_reference_t</span><span class="special">&lt;</span><span class="identifier">Member</span><span class="special">&gt;;</span> <span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">ptr_type</span> <span class="special">=</span> <span class="identifier">Member</span> <span class="identifier">U</span><span class="special">::*;</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">qualifiers</span> <span class="special">=</span> <span class="special">\</span>
<span class="keyword">decltype</span><span class="special">(</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">get_qualifier_flags</span><span class="special">&lt;</span><span class="identifier">Member</span><span class="special">&gt;());</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">type_erased_ptr</span> <span class="special">=</span> <span class="identifier">result_type</span><span class="special">(*)(</span><span class="keyword">void</span><span class="special">*);</span> <span class="special">\</span>
<span class="special">};</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">U</span><span class="special">&gt;</span> <span class="special">\</span>
<span class="keyword">struct</span> <span class="identifier">member_info</span> <span class="special">&lt;</span><span class="identifier">U</span><span class="special">,</span> <span class="identifier">member_type</span><span class="special">,</span> <span class="keyword">true</span><span class="special">&gt;</span> <span class="special">{</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">ptr_type</span> <span class="special">=</span> <span class="identifier">member_type</span> <span class="identifier">U</span><span class="special">::*;</span> <span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">result_type</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">&lt;</span><span class="identifier">ptr_type</span><span class="special">&gt;;</span> <span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">function_type</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">function_type</span><span class="special">&lt;</span><span class="identifier">ptr_type</span><span class="special">&gt;;</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">qualifiers</span> <span class="special">=</span> <span class="keyword">decltype</span><span class="special">(</span> <span class="special">\</span>
<span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">get_member_qualifier_flags</span><span class="special">&lt;</span><span class="identifier">ptr_type</span><span class="special">&gt;());</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">type_erased_ptr</span> <span class="special">=</span> <span class="special">\</span>
<span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">replace_args</span><span class="special">&lt;</span><span class="number">0</span><span class="special">,</span> <span class="identifier">function_type</span><span class="special">,</span> <span class="keyword">void</span><span class="special">*&gt;</span> <span class="special">*;</span> <span class="special">\</span>
<span class="special">};</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">info</span> <span class="special">=</span> <span class="identifier">member_info</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;;</span> <span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">ptr_type</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">info</span><span class="special">::</span><span class="identifier">ptr_type</span><span class="special">;</span> <span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">result_type</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">info</span><span class="special">::</span><span class="identifier">result_type</span><span class="special">;</span> <span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">type_erased_ptr</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">info</span><span class="special">::</span><span class="identifier">type_erased_ptr</span><span class="special">;</span> <span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">qualifiers</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">info</span><span class="special">::</span><span class="identifier">qualifiers</span><span class="special">;</span> <span class="special">\</span>
<span class="special">};</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">pmf</span><span class="special">,</span> <span class="identifier">i</span><span class="special">)</span> <span class="special">=</span> <span class="special">\</span>
<span class="keyword">typename</span> <span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">member_info</span><span class="special">,</span> <span class="identifier">i</span><span class="special">)&lt;&gt;::</span><span class="identifier">ptr_type</span><span class="special">;</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">typename</span> <span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">member_info</span><span class="special">,</span> <span class="identifier">i</span><span class="special">)&lt;&gt;</span> <span class="special">\</span>
<span class="special">::</span><span class="identifier">type_erased_ptr</span> <span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">func</span><span class="special">,</span> <span class="identifier">i</span><span class="special">);</span> <span class="special">\</span>
<span class="comment">/**/</span>
<span class="comment">// generate the bases, each of which will contain a public-facing</span>
<span class="comment">// interface function</span>
<span class="preprocessor">#define</span> <span class="identifier">CALLABLE_TRAITS_INTERFACE__BASES</span><span class="special">(</span><span class="identifier">z</span><span class="special">,</span><span class="identifier">i</span><span class="special">,</span><span class="identifier">seq</span><span class="special">)</span> <span class="special">\</span>
<span class="identifier">CALLABLE_TRAITS_INTERFACE__BASES_I</span><span class="special">(</span><span class="identifier">i</span><span class="special">,</span> <span class="special">\</span>
<span class="identifier">BOOST_PP_TUPLE_ELEM</span><span class="special">(</span><span class="number">2</span><span class="special">,</span><span class="number">0</span><span class="special">,</span><span class="identifier">BOOST_PP_SEQ_ELEM</span><span class="special">(</span><span class="identifier">i</span><span class="special">,</span><span class="identifier">seq</span><span class="special">)))</span> <span class="special">\</span>
<span class="comment">/**/</span>
<span class="preprocessor">#define</span> <span class="identifier">CALLABLE_TRAITS_INTERFACE__BASES_I</span><span class="special">(</span><span class="identifier">i</span><span class="special">,</span> <span class="identifier">mem</span><span class="special">)</span> <span class="special">\</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span><span class="special">...</span> <span class="identifier">Args</span><span class="special">&gt;</span> <span class="special">\</span>
<span class="keyword">struct</span> <span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">base_impl</span><span class="special">,</span> <span class="identifier">i</span><span class="special">)</span> <span class="special">{</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">template</span><span class="special">&lt;::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">flags</span> <span class="identifier">QualifierFlags</span><span class="special">,</span> <span class="special">\</span>
<span class="keyword">typename</span> <span class="identifier">Base</span> <span class="special">=</span> <span class="identifier">get_next_base</span><span class="special">&lt;</span><span class="identifier">i</span><span class="special">&gt;&gt;</span> <span class="special">\</span>
<span class="keyword">struct</span> <span class="identifier">apply</span><span class="special">;</span> <span class="special">\</span>
<span class="special">\</span>
<span class="identifier">CALLABLE_TRAITS_INTERFACE__BASES_APPLY</span><span class="special">(</span><span class="identifier">i</span><span class="special">,</span> <span class="identifier">mem</span><span class="special">,</span> <span class="special">\</span>
<span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">default_</span><span class="special">,</span> <span class="identifier">BOOST_PP_EMPTY</span><span class="special">())</span> <span class="special">\</span>
<span class="special">\</span>
<span class="identifier">CALLABLE_TRAITS_INTERFACE__BASES_APPLY</span><span class="special">(</span><span class="identifier">i</span><span class="special">,</span> <span class="identifier">mem</span><span class="special">,</span> <span class="special">\</span>
<span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">const_</span><span class="special">,</span> <span class="keyword">const</span><span class="special">)</span> <span class="special">\</span>
<span class="special">\</span>
<span class="identifier">CALLABLE_TRAITS_INTERFACE__BASES_APPLY</span><span class="special">(</span><span class="identifier">i</span><span class="special">,</span> <span class="identifier">mem</span><span class="special">,</span> <span class="special">\</span>
<span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">volatile_</span><span class="special">,</span> <span class="keyword">volatile</span><span class="special">)</span> <span class="special">\</span>
<span class="special">\</span>
<span class="identifier">CALLABLE_TRAITS_INTERFACE__BASES_APPLY</span><span class="special">(</span><span class="identifier">i</span><span class="special">,</span> <span class="identifier">mem</span><span class="special">,</span> <span class="special">\</span>
<span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">const_</span> <span class="special">|</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">volatile_</span><span class="special">),</span> <span class="keyword">const</span> <span class="keyword">volatile</span><span class="special">)\</span>
<span class="special">};</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Ignored</span><span class="special">&gt;</span> <span class="special">\</span>
<span class="keyword">struct</span> <span class="identifier">base</span><span class="special">&lt;</span><span class="identifier">i</span><span class="special">,</span> <span class="identifier">Ignored</span><span class="special">&gt;</span> <span class="special">{</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">function_type</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">function_type</span><span class="special">&lt;</span> <span class="special">\</span>
<span class="keyword">typename</span> <span class="identifier">interface_root</span><span class="special">::</span><span class="identifier">vtable</span><span class="special">::</span><span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">pmf</span><span class="special">,</span> <span class="identifier">i</span><span class="special">)&gt;;</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">impl</span> <span class="special">=</span> <span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">expand_args</span><span class="special">&lt;</span> <span class="special">\</span>
<span class="special">::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">ct</span><span class="special">::</span><span class="identifier">pop_front</span><span class="special">&lt;</span><span class="identifier">function_type</span><span class="special">&gt;,</span> <span class="special">\</span>
<span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">base_impl</span><span class="special">,</span> <span class="identifier">i</span><span class="special">)&gt;;</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">qualifiers</span> <span class="special">=</span> <span class="special">\</span>
<span class="keyword">typename</span> <span class="identifier">interface_root</span><span class="special">::</span><span class="identifier">vtable</span><span class="special">::</span><span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">member_info</span><span class="special">,</span> <span class="identifier">i</span><span class="special">)&lt;&gt;\</span>
<span class="special">::</span><span class="identifier">qualifiers</span><span class="special">;</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">type</span> <span class="special">=</span> <span class="identifier">impl</span><span class="special">::</span><span class="keyword">template</span> <span class="identifier">apply</span><span class="special">&lt;</span><span class="identifier">qualifiers</span><span class="special">::</span><span class="identifier">value</span><span class="special">&gt;;</span> <span class="special">\</span>
<span class="special">};</span> <span class="special">\</span>
<span class="comment">/**/</span>
<span class="comment">// generate specializations based on qualifiers on member functions/data.</span>
<span class="comment">// lvalue and rvalue member functions are ignored.</span>
<span class="preprocessor">#define</span> <span class="identifier">CALLABLE_TRAITS_INTERFACE__BASES_APPLY</span><span class="special">(</span><span class="identifier">i</span><span class="special">,</span> <span class="identifier">mem</span><span class="special">,</span> <span class="identifier">flags</span><span class="special">,</span> <span class="identifier">qualifiers</span><span class="special">)</span> <span class="special">\</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Base</span><span class="special">&gt;</span> <span class="special">\</span>
<span class="keyword">struct</span> <span class="identifier">apply</span><span class="special">&lt;</span><span class="identifier">flags</span><span class="special">,</span> <span class="identifier">Base</span><span class="special">&gt;</span> <span class="special">:</span> <span class="identifier">Base</span> <span class="special">{</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">Base</span><span class="special">;</span> <span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">ptr_vtable</span><span class="special">;</span> <span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">obj_ptr</span><span class="special">;</span> <span class="special">\</span>
<span class="special">\</span>
<span class="keyword">inline</span> <span class="keyword">decltype</span><span class="special">(</span><span class="keyword">auto</span><span class="special">)</span> <span class="special">\</span>
<span class="identifier">mem</span><span class="special">(::</span><span class="identifier">intrfc</span><span class="special">::</span><span class="identifier">forward_t</span><span class="special">&lt;</span><span class="identifier">Args</span><span class="special">&gt;...</span> <span class="identifier">args</span><span class="special">)</span> <span class="identifier">qualifiers</span> <span class="special">{</span> <span class="special">\</span>
<span class="keyword">return</span> <span class="identifier">ptr_vtable</span><span class="special">-&gt;</span><span class="identifier">BOOST_PP_CAT</span><span class="special">(</span><span class="identifier">func</span><span class="special">,</span> <span class="identifier">i</span><span class="special">)(</span><span class="identifier">obj_ptr</span><span class="special">,</span> <span class="identifier">args</span><span class="special">...);\</span>
<span class="special">}</span> <span class="special">\</span>
<span class="special">};</span> <span class="special">\</span>
<span class="comment">/**/</span>
<span class="preprocessor">#define</span> <span class="identifier">CALLABLE_TRAITS_INTERFACE__USING_DECLARATIONS</span><span class="special">(</span><span class="identifier">z</span><span class="special">,</span><span class="identifier">i</span><span class="special">,</span><span class="identifier">seq</span><span class="special">)</span> <span class="special">\</span>
<span class="keyword">using</span> <span class="identifier">detail</span><span class="special">::</span><span class="identifier">base</span><span class="special">&lt;</span><span class="identifier">i</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">::</span> <span class="special">\</span>
<span class="identifier">BOOST_PP_TUPLE_ELEM</span><span class="special">(</span><span class="number">2</span><span class="special">,</span><span class="number">0</span><span class="special">,</span><span class="identifier">BOOST_PP_SEQ_ELEM</span><span class="special">(</span><span class="identifier">i</span><span class="special">,</span><span class="identifier">seq</span><span class="special">));</span> <span class="special">\</span>
<span class="comment">/**/</span>
</pre>
<p>
See also: <a href="http://www.coderage.com/interfaces/" target="_top">Boost.Interfaces
(sic)</a>
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2016 Barrett Adair<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE.md 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></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="callable_traits/example_std_function_sugar.html"><img src="../src/images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="../src/images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="../src/images/home.png" alt="Home"></a><a accesskey="n" href="callable_traits/contact.html"><img src="../src/images/next.png" alt="Next"></a>
</div>
</body>
</html>