with_vptr -> inplace_vptr

This commit is contained in:
Jean-Louis Leroy
2025-07-12 10:19:35 -04:00
parent 0416b9b888
commit baff0d3f23
14 changed files with 106 additions and 101 deletions

View File

@@ -8,7 +8,7 @@ called to rebuild the dispatch tables.
This leads to a problem: any `virtual_ptr` in existence before `initialize` is
called again becomes invalid. This also applies to vptrs that are stored inside
objects by `with_vptr`.
objects by `inplace_vptr`.
NOTE: This applies only to cases where a dynamic library adds to an _existing_
policy. Even if the dynamic library itself uses open-methods, for example as an

View File

@@ -610,7 +610,7 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
<li><a href="#virtual_ptr_description_4">Description</a></li>
</ul>
</li>
<li><a href="#virtual_ptr_with_vptr">with_vptr</a>
<li><a href="#virtual_ptr_inplace_vptr">inplace_vptr</a>
<ul class="sectlevel3">
<li><a href="#virtual_ptr_synopsis_5">Synopsis</a></li>
<li><a href="#virtual_ptr_description_5">Description</a></li>
@@ -1961,17 +1961,17 @@ required by the library.
</table>
</div>
<div class="paragraph">
<p>The <code>with_vptr</code> CRTP class automates the creation and management of embedded
<p>The <code>inplace_vptr</code> CRTP class automates the creation and management of embedded
vptrs.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="c++">#include &lt;boost/openmethod/with_vptr.hpp&gt;
<pre class="rouge highlight"><code data-lang="c++">#include &lt;boost/openmethod/inplace_vptr.hpp&gt;
class Animal : public boost::openmethod::with_vptr&lt;Animal&gt; {
class Animal : public boost::openmethod::inplace_vptr&lt;Animal&gt; {
};
class Cat : public Animal, public boost::openmethod::with_vptr&lt;Cat, Animal&gt; {
class Cat : public Animal, public boost::openmethod::inplace_vptr&lt;Cat, Animal&gt; {
};
BOOST_OPENMETHOD(poke, (std::ostream&amp;, virtual_&lt;Animal&amp;&gt;), void);
@@ -1989,11 +1989,11 @@ int main() {
</div>
</div>
<div class="paragraph">
<p>If <code>with_vptr</code> is passed only the class being defined, it adds a vptr to it, and
<p>If <code>inplace_vptr</code> is passed only the class being defined, it adds a vptr to it, and
defines a <code>boost_openmethod_vptr</code> friend function. If more classes are passed,
they must be the direct bases of the class potentially involved in open-method
calls. Its constructor and destructor set the vptr to point to the v-table for
the class. <code>with_vptr</code> also takes care of registering the classes, so this time
the class. <code>inplace_vptr</code> also takes care of registering the classes, so this time
the call to <code>BOOST_OPENMETHOD_CLASSES</code> is not needed.</p>
</div>
</div>
@@ -2787,7 +2787,7 @@ called to rebuild the dispatch tables.</p>
<div class="paragraph">
<p>This leads to a problem: any <code>virtual_ptr</code> in existence before <code>initialize</code> is
called again becomes invalid. This also applies to vptrs that are stored inside
objects by <code>with_vptr</code>.</p>
objects by <code>inplace_vptr</code>.</p>
</div>
<div class="admonitionblock note">
<table>
@@ -3131,7 +3131,7 @@ virtual parameters.</p>
</div>
</div>
<div class="sect4">
<h5 id="ref_boostopenmethodwith_vptr_hpp">&lt;boost/openmethod/with_vptr.hpp&gt;</h5>
<h5 id="ref_boostopenmethodinplace_vptr_hpp">&lt;boost/openmethod/inplace_vptr.hpp&gt;</h5>
<div class="paragraph">
<p>Provides support for storing v-table pointers directly in objects, in the same
manner as native virtual functions.</p>
@@ -4811,29 +4811,29 @@ more information.</p>
</div>
</div>
<div class="sect2">
<h3 id="virtual_ptr_with_vptr">with_vptr</h3>
<h3 id="virtual_ptr_inplace_vptr">inplace_vptr</h3>
<div class="sect3">
<h4 id="virtual_ptr_synopsis_5">Synopsis</h4>
<div class="paragraph">
<p>Defined in &lt;boost/openmethod/with_vptr.hpp&gt;.</p>
<p>Defined in &lt;boost/openmethod/inplace_vptr.hpp&gt;.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="c++">namespace boost::openmethod {
template&lt;class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY&gt;
class with_vptr {
class inplace_vptr {
protected:
with_vptr();
~with_vptr();
inplace_vptr();
~inplace_vptr();
friend auto boost_openmethod_vptr(const Class&amp; obj) -&gt; vptr_type;
};
template&lt;class Class, class Base, class... MoreBases&gt;
class with_vptr {
class inplace_vptr {
protected:
with_vptr();
~with_vptr();
inplace_vptr();
~inplace_vptr();
friend auto boost_openmethod_vptr(const Class&amp; obj) -&gt; vptr_type;
// if sizeof(MoreBases...) &gt; 0
};
@@ -4845,11 +4845,11 @@ class with_vptr {
<div class="sect3">
<h4 id="virtual_ptr_description_5">Description</h4>
<div class="paragraph">
<p><code>with_vptr</code> is a CRTP class template that embeds and manages a vptr across a
<p><code>inplace_vptr</code> is a CRTP class template that embeds and manages a vptr across a
class hierarchy.</p>
</div>
<div class="paragraph">
<p>If <code>Class</code> has no <code>Bases</code>, <code>with_vptr</code> adds a <code>boost_openmethod_vptr</code> private
<p>If <code>Class</code> has no <code>Bases</code>, <code>inplace_vptr</code> adds a <code>boost_openmethod_vptr</code> private
member to <code>Class</code>. In either case, it sets the vptr to the v-table of <code>Class</code>
from <code>Policy</code>. It also creates a <code>boost_openmethod_vptr</code> friend function that
takes a a <code>const Class&amp;</code> and returns the embedded vptr.</p>
@@ -4861,7 +4861,7 @@ matter which one, as they all have the same value). This is to resolve
ambiguities</p>
</div>
<div class="paragraph">
<p>As part of its implementation, <code>with_vptr</code> may also declare one or two free
<p>As part of its implementation, <code>inplace_vptr</code> may also declare one or two free
functions (<code>boost_openmethod_policy</code> and <code>boost_openmethod_bases</code>) at certain
levels of the hierarchy.</p>
</div>
@@ -4872,7 +4872,7 @@ levels of the hierarchy.</p>
<h5 id="virtual_ptr_constructor_2">constructor</h5>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="c++">with_vptr();</code></pre>
<pre class="rouge highlight"><code data-lang="c++">inplace_vptr();</code></pre>
</div>
</div>
<div class="paragraph">
@@ -4885,7 +4885,7 @@ preserving the validity of the pointer across calls to <code>initialize</code>.<
<h5 id="virtual_ptr_destructor_2">destructor</h5>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="c++">~with_vptr();</code></pre>
<pre class="rouge highlight"><code data-lang="c++">~inplace_vptr();</code></pre>
</div>
</div>
<div class="paragraph">
@@ -5612,7 +5612,7 @@ the same.</p>
<div class="sect3">
<h4 id="virtual_ptr_description_15">Description</h4>
<div class="paragraph">
<p><code>indirect_vptr</code> is a facet that makes <code>virtual_ptr</code>s and <code>with_vptr</code> use
<p><code>indirect_vptr</code> is a facet that makes <code>virtual_ptr</code>s and <code>inplace_vptr</code> use
pointers to pointers to v-tables, instead of straight pointers. As a
consequence, they remain valid after a call to <code>initialize</code>.</p>
</div>
@@ -6249,7 +6249,7 @@ the library uses a lightweight implementation based on the C stream functions.</
</div>
<div id="footer">
<div id="footer-text">
Last updated 2025-03-08 15:24:21 -0500
Last updated 2025-06-22 13:38:14 -0400
</div>
</div>
</body>

View File

@@ -1,26 +1,26 @@
## with_vptr
## inplace_vptr
### Synopsis
Defined in <boost/openmethod/with_vptr.hpp>.
Defined in <boost/openmethod/inplace_vptr.hpp>.
```c++
namespace boost::openmethod {
template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
class with_vptr {
class inplace_vptr {
protected:
with_vptr();
~with_vptr();
inplace_vptr();
~inplace_vptr();
friend auto boost_openmethod_vptr(const Class& obj) -> vptr_type;
};
template<class Class, class Base, class... MoreBases>
class with_vptr {
class inplace_vptr {
protected:
with_vptr();
~with_vptr();
inplace_vptr();
~inplace_vptr();
friend auto boost_openmethod_vptr(const Class& obj) -> vptr_type;
// if sizeof(MoreBases...) > 0
};
@@ -30,10 +30,10 @@ class with_vptr {
### Description
`with_vptr` is a CRTP class template that embeds and manages a vptr across a
`inplace_vptr` is a CRTP class template that embeds and manages a vptr across a
class hierarchy.
If `Class` has no `Bases`, `with_vptr` adds a `boost_openmethod_vptr` private
If `Class` has no `Bases`, `inplace_vptr` adds a `boost_openmethod_vptr` private
member to `Class`. In either case, it sets the vptr to the v-table of `Class`
from `Policy`. It also creates a `boost_openmethod_vptr` friend function that
takes a a `const Class&` and returns the embedded vptr.
@@ -43,7 +43,7 @@ function is also created. It returns one of the embedded vptrs (it doesn't
matter which one, as they all have the same value). This is to resolve
ambiguities
As part of its implementation, `with_vptr` may also declare one or two free
As part of its implementation, `inplace_vptr` may also declare one or two free
functions (`boost_openmethod_policy` and `boost_openmethod_bases`) at certain
levels of the hierarchy.
@@ -52,7 +52,7 @@ levels of the hierarchy.
#### constructor
```c++
with_vptr();
inplace_vptr();
```
Sets the vptr to the v-table for Class, obtained from `Policy`. If `Policy`
@@ -63,7 +63,7 @@ preserving the validity of the pointer across calls to `initialize`.
#### destructor
```c++
~with_vptr();
~inplace_vptr();
```
For each `Base`, sets the vptr to the v-table for that base.

View File

@@ -83,7 +83,7 @@ virtual parameters.
Provides support for using `std::unique_ptr` in place of plain pointers in
virtual parameters.
#### <boost/openmethod/with_vptr.hpp>
#### <boost/openmethod/inplace_vptr.hpp>
Provides support for storing v-table pointers directly in objects, in the same
manner as native virtual functions.

View File

@@ -27,7 +27,7 @@ include::virtual_ptr.adoc[]
include::virtual_traits.adoc[]
include::use_classes.adoc[]
include::virtual_.adoc[]
include::with_vptr.adoc[]
include::inplace_vptr.adoc[]
include::abstract_policy.adoc[]
include::domain.adoc[]
include::basic_policy.adoc[]

View File

@@ -53,12 +53,12 @@ NOTE: With this approach, classes need not be polymorphic. A virtual
destructor might be needed for correct destruction of objects, but it is not
required by the library.
The `with_vptr` CRTP class automates the creation and management of embedded
The `inplace_vptr` CRTP class automates the creation and management of embedded
vptrs.
[source,c++]
----
include::{exampledir}/virtual_.cpp[tag=with_vptr,indent=0]
include::{exampledir}/virtual_.cpp[tag=inplace_vptr,indent=0]
int main() {
boost::openmethod::initialize();
@@ -68,9 +68,9 @@ int main() {
}
----
If `with_vptr` is passed only the class being defined, it adds a vptr to it, and
If `inplace_vptr` is passed only the class being defined, it adds a vptr to it, and
defines a `boost_openmethod_vptr` friend function. If more classes are passed,
they must be the direct bases of the class potentially involved in open-method
calls. Its constructor and destructor set the vptr to point to the v-table for
the class. `with_vptr` also takes care of registering the classes, so this time
the class. `inplace_vptr` also takes care of registering the classes, so this time
the call to `BOOST_OPENMETHOD_CLASSES` is not needed.

View File

@@ -55,7 +55,7 @@ struct indirect_vptr : facet {};
### Description
`indirect_vptr` is a facet that makes `virtual_ptr`{empty}s and `with_vptr` use
`indirect_vptr` is a facet that makes `virtual_ptr`{empty}s and `inplace_vptr` use
pointers to pointers to v-tables, instead of straight pointers. As a
consequence, they remain valid after a call to `initialize`.

View File

@@ -6,7 +6,7 @@
#include <iostream>
#include <boost/openmethod.hpp>
#include <boost/openmethod/with_vptr.hpp>
#include <boost/openmethod/inplace_vptr.hpp>
#include <boost/openmethod/compiler.hpp>
using boost::openmethod::virtual_;
@@ -68,16 +68,16 @@ BOOST_OPENMETHOD_CLASSES(Animal, Cat);
// end::virtual_intrusive[]
} // namespace virtual_intrusive
namespace with_vptr {
namespace inplace_vptr {
// tag::with_vptr[]
// tag::inplace_vptr[]
#include <boost/openmethod/with_vptr.hpp>
#include <boost/openmethod/inplace_vptr.hpp>
class Animal : public boost::openmethod::with_vptr<Animal> {
class Animal : public boost::openmethod::inplace_vptr<Animal> {
};
class Cat : public Animal, public boost::openmethod::with_vptr<Cat, Animal> {
class Cat : public Animal, public boost::openmethod::inplace_vptr<Cat, Animal> {
};
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_<Animal&>), void);
@@ -85,9 +85,9 @@ BOOST_OPENMETHOD(poke, (std::ostream&, virtual_<Animal&>), void);
BOOST_OPENMETHOD_OVERRIDE(poke, (std::ostream & os, Cat& /*cat*/), void) {
os << "hiss\n";
}
// end::with_vptr[]
// end::inplace_vptr[]
} // namespace with_vptr
} // namespace inplace_vptr
auto main() -> int {
boost::openmethod::initialize();
@@ -105,7 +105,7 @@ auto main() -> int {
}
{
using namespace with_vptr;
using namespace inplace_vptr;
Cat cat;
poke(std::cout, cat); // hiss
}

View File

@@ -981,8 +981,8 @@ template<typename T, class Registry>
struct valid_method_parameter<virtual_<T>, Registry>
: std::bool_constant<
has_vptr_fn<virtual_type<T, Registry>, Registry> ||
Registry::rtti::template is_polymorphic<
virtual_type<T, Registry>>> {};
Registry::rtti::template is_polymorphic<virtual_type<T, Registry>>> {
};
} // namespace detail

View File

@@ -1,10 +1,10 @@
#ifndef BOOST_OPENMETHOD_WITH_VPTR_HPP
#define BOOST_OPENMETHOD_WITH_VPTR_HPP
#ifndef BOOST_OPENMETHOD_inplace_vptr_HPP
#define BOOST_OPENMETHOD_inplace_vptr_HPP
#include <boost/openmethod/core.hpp>
// =============================================================================
// with_vptr
// inplace_vptr
namespace boost::openmethod {
@@ -14,7 +14,7 @@ void boost_openmethod_registry(...);
void boost_openmethod_bases(...);
template<class Class>
using with_vptr_registry =
using inplace_vptr_registry =
decltype(boost_openmethod_registry(std::declval<Class*>()));
template<class>
@@ -33,7 +33,7 @@ struct update_vptr_bases<mp11::mp_list<Bases...>> {
template<class To, class Class>
void update_vptr(Class* obj) {
using registry = with_vptr_registry<Class>;
using registry = inplace_vptr_registry<Class>;
using bases = decltype(boost_openmethod_bases(obj));
if constexpr (mp11::mp_size<bases>::value == 0) {
@@ -47,32 +47,32 @@ void update_vptr(Class* obj) {
}
}
struct with_vptr_derived {};
struct inplace_vptr_derived {};
template<class, class, bool>
class with_vptr_aux;
class inplace_vptr_aux;
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic ignored "-Wnon-template-friend"
#endif
template<class... Classes>
inline use_classes<Classes...> with_vptr_use_classes;
inline use_classes<Classes...> inplace_vptr_use_classes;
template<class Class, class Registry>
class with_vptr_aux<Class, Registry, true> {
class inplace_vptr_aux<Class, Registry, true> {
protected:
template<class To, class Other>
friend void update_vptr(Other*);
friend auto boost_openmethod_registry(Class*) -> Registry;
friend auto boost_openmethod_bases(Class*) -> mp11::mp_list<>;
with_vptr_aux() {
(void)&with_vptr_use_classes<Class, Registry>;
inplace_vptr_aux() {
(void)&inplace_vptr_use_classes<Class, Registry>;
detail::update_vptr<Class>(static_cast<Class*>(this));
}
~with_vptr_aux() {
~inplace_vptr_aux() {
boost_openmethod_vptr = nullptr;
}
@@ -92,16 +92,17 @@ class with_vptr_aux<Class, Registry, true> {
};
template<class Class, class Base>
class with_vptr_aux<Class, Base, false> : with_vptr_derived {
class inplace_vptr_aux<Class, Base, false> : inplace_vptr_derived {
protected:
friend void update_vptr(Class*);
with_vptr_aux() {
(void)&with_vptr_use_classes<Class, Base, with_vptr_registry<Class>>;
inplace_vptr_aux() {
(void)&inplace_vptr_use_classes<
Class, Base, inplace_vptr_registry<Class>>;
detail::update_vptr<Class>(static_cast<Class*>(this));
}
~with_vptr_aux() {
~inplace_vptr_aux() {
detail::update_vptr<Base>(
static_cast<Base*>(static_cast<Class*>(this)));
}
@@ -112,18 +113,21 @@ class with_vptr_aux<Class, Base, false> : with_vptr_derived {
} // namespace detail
template<typename...>
class with_vptr;
class inplace_vptr;
template<class Class>
class with_vptr<Class> : public detail::with_vptr_aux<
Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY, true> {};
class inplace_vptr<Class>
: public detail::inplace_vptr_aux<
Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY, true> {};
template<class Class, class Other>
class with_vptr<Class, Other>
: public detail::with_vptr_aux<Class, Other, detail::is_registry<Other>> {};
class inplace_vptr<Class, Other>
: public detail::inplace_vptr_aux<
Class, Other, detail::is_registry<Other>> {};
template<class Class, class Base1, class Base2, class... MoreBases>
class with_vptr<Class, Base1, Base2, MoreBases...> : detail::with_vptr_derived {
class inplace_vptr<Class, Base1, Base2, MoreBases...>
: detail::inplace_vptr_derived {
static_assert(
!detail::is_registry<Base1> && !detail::is_registry<Base2> &&
@@ -131,14 +135,14 @@ class with_vptr<Class, Base1, Base2, MoreBases...> : detail::with_vptr_derived {
"registry can be specified only for root classes");
protected:
with_vptr() {
(void)&detail::with_vptr_use_classes<
inplace_vptr() {
(void)&detail::inplace_vptr_use_classes<
Class, Base1, Base2, MoreBases...,
detail::with_vptr_registry<Base1>>;
detail::inplace_vptr_registry<Base1>>;
detail::update_vptr<Class>(static_cast<Class*>(this));
}
~with_vptr() {
~inplace_vptr() {
auto obj = static_cast<Class*>(this);
detail::update_vptr<Base1>(static_cast<Base1*>(obj));
detail::update_vptr<Base2>(static_cast<Base2*>(obj));
@@ -146,11 +150,11 @@ class with_vptr<Class, Base1, Base2, MoreBases...> : detail::with_vptr_derived {
}
friend auto boost_openmethod_registry(Class*)
-> detail::with_vptr_registry<Base1>;
-> detail::inplace_vptr_registry<Base1>;
friend auto boost_openmethod_bases(Class*)
-> mp11::mp_list<Base1, Base2, MoreBases...>;
friend auto boost_openmethod_vptr(
const Class& obj, detail::with_vptr_registry<Base1>* registry)
const Class& obj, detail::inplace_vptr_registry<Base1>* registry)
-> vptr_type {
return boost_openmethod_vptr(static_cast<const Base1&>(obj), registry);
}
@@ -158,4 +162,4 @@ class with_vptr<Class, Base1, Base2, MoreBases...> : detail::with_vptr_derived {
} // namespace boost::openmethod
#endif // BOOST_OPENMETHOD_WITH_VPTR_HPP
#endif // BOOST_OPENMETHOD_inplace_vptr_HPP

View File

@@ -9,4 +9,5 @@ using namespace boost::openmethod;
struct Cat {};
BOOST_OPENMETHOD(poke, (virtual_ptr<Cat, release_registry>), void, debug_registry);
BOOST_OPENMETHOD(
poke, (virtual_ptr<Cat, release_registry>), void, debug_registry);

View File

@@ -16,7 +16,7 @@ using namespace boost::openmethod::detail;
namespace mp11 = boost::mp11;
#include <boost/openmethod.hpp>
#include <boost/openmethod/with_vptr.hpp>
#include <boost/openmethod/inplace_vptr.hpp>
#include <boost/openmethod/shared_ptr.hpp>
#include "test_util.hpp"
@@ -149,17 +149,18 @@ struct non_polymorphic {};
static_assert(!valid_method_parameter<
virtual_<non_polymorphic&>, default_registry>::value);
struct non_polymorphic_with_vptr {};
struct non_polymorphic_inplace_vptr {};
auto boost_openmethod_vptr(const non_polymorphic_with_vptr&, void*)
auto boost_openmethod_vptr(const non_polymorphic_inplace_vptr&, void*)
-> vptr_type;
static_assert(valid_method_parameter<
virtual_<non_polymorphic_with_vptr&>, default_registry>::value);
static_assert(
valid_method_parameter<
virtual_<const non_polymorphic_with_vptr&>, default_registry>::value);
virtual_<non_polymorphic_inplace_vptr&>, default_registry>::value);
static_assert(valid_method_parameter<
virtual_<const non_polymorphic_inplace_vptr&>,
default_registry>::value);
// clang-format on

View File

@@ -16,7 +16,7 @@ struct test_registry
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY test_registry
#include <boost/openmethod.hpp>
#include <boost/openmethod/with_vptr.hpp>
#include <boost/openmethod/inplace_vptr.hpp>
#include <boost/openmethod/shared_ptr.hpp>
#include <boost/openmethod/compiler.hpp>
@@ -26,25 +26,25 @@ struct test_registry
namespace bom = boost::openmethod;
using bom::virtual_;
struct Animal : bom::with_vptr<Animal> {
struct Animal : bom::inplace_vptr<Animal> {
explicit Animal(std::ostream& os);
~Animal();
std::ostream& os;
};
struct Cat : Animal, bom::with_vptr<Cat, Animal> {
struct Cat : Animal, bom::inplace_vptr<Cat, Animal> {
explicit Cat(std::ostream& os);
~Cat();
};
struct Pet : bom::with_vptr<Pet> {
struct Pet : bom::inplace_vptr<Pet> {
explicit Pet(std::ostream& os);
~Pet();
std::string name;
std::ostream& os;
};
struct DomesticCat : Cat, Pet, bom::with_vptr<DomesticCat, Cat, Pet> {
struct DomesticCat : Cat, Pet, bom::inplace_vptr<DomesticCat, Cat, Pet> {
explicit DomesticCat(std::ostream& os);
~DomesticCat();
};
@@ -182,8 +182,8 @@ BOOST_AUTO_TEST_CASE(intrusive_mode) {
struct indirect_policy : test_registry::with<bom::policies::indirect_vptr> {};
struct Indirect : bom::with_vptr<Indirect, indirect_policy> {
using bom::with_vptr<Indirect, indirect_policy>::boost_openmethod_vptr;
struct Indirect : bom::inplace_vptr<Indirect, indirect_policy> {
using bom::inplace_vptr<Indirect, indirect_policy>::boost_openmethod_vptr;
};
BOOST_OPENMETHOD(whatever, (virtual_<Indirect&>), void, indirect_policy);

View File

@@ -3,7 +3,6 @@
// See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_TEST_MODULE static_list
#include <boost/test/unit_test.hpp>