YOMM2 is a library that implements open multi-methods for C++17. The semantics of methods are strongly influenced by the Open Multi-Methods for C++ paper by Peter Pirkelbauer, Yuriy Solodkyy, and Bjarne Stroustrup.
This implementation diverges from the paper on the following points:
next
) to call the next most specialised method.method_container
.A method is a function that has one or more virtual parameters, and a collection of method definitions.
A method definition is a function attached to a single method. The type of the parameters corresponding to the virtual parameters in the method must be compatible with the method’s parameter type. The other parameters must have the same type as in the method. The return type of the definition must be compatible with the return type of the method.
A virtual parameter is a parameter that is taken into account when the method is called.
A virtual argument is an argument in a method call that corresponds to a virtual parameter in the method declaration. The method uses the dynamic type of the virtual arguments to select which definition to execute. The rules for selecting the definition are the same as for overload resolution: use the most specialised definition, from the set of applicable definitions. However, note that the selection happens at runtime.
The library is normally used via the keyword interface, provided by the
<yorel/yomm2/keywords.hpp>
header. It attempts to present open methods as a
language feature. It consists of a collection of macros, which are, of course,
global, but so are keywords. The virtual_ template, used to specify
virtual parameters, is also aliases in the global namespace.
The library can also be used through the core interface, which is almost entirely free of macros. The primary use of this interface is to support templatized classes, methods and definitions - something that macros are incapable of. See the templates tutorial for more details and examples.
YOMM2 is exception agnostic. The library does not throw nor catches exceptions, but it is exception safe. Errors are reported via an indirect call to a handler function, which can be set with set_error_handler. A handler may throw exceptions.
<yorel/yomm2/keywords.hpp>
This header provides the keyword interface. Since version 1.3.0, this is the recommended main header for normal usage of the library. It is used in most examples and tutorials. The header makes it look like the library’s features are part of the language:
<yorel/yomm2/core.hpp>
.<yorel/yomm2/cute.hpp>
, thus making the lowercase macros
(declare_method
, etc) available.using ::yorel::yomm2::virtual_
directive.<yorel/yomm2/core.hpp>
This header provides the core interface, in the yorel::yomm2
namespace.
Since version 1.3.0, the key mechanisms are documented; thus, it possible to use
the library without resorting on the macros. See the API
tutorial for an introduction to the main features of
core
.
The main constructs are:
method
, a class template that contains:
fn
, to call the methodadd_function
and add_definition
, to add
definitions to a methodnext_type
and use_next
, to call the next most
specialised methoduse_classes
, a class template, provides the class and inheritance information.update
, a function that calculates the method dispatch tables, using the
method, definition, and class information.The header itself does not define any macros, except for its include guard
(YOREL_YOMM2_CORE_INCLUDED
).
The header consumes three macros:
NDEBUG
: if defined, no checks are performed during method calls. This
delivers a performance close to normal virtual function calls.YOMM2_SHARED
: if defined, the library runtime is in a shared library or DLL.YOMM2_DEFAULT_POLICY
: if defined, overrides the default policy.The header defines the following macros:
YOREL_YOMM2_CORE_INCLUDED
).YOMM2_SHARED
is defined, a yOMM2_API
macro, for internal use.<yorel/yomm2/policy.hpp>
Contains the policy namespace, and the associated mechanisms. It is included by
<yorel/yomm2/core.hpp>
. It can also be included directly to create a new
policy, to be used as the default policy, before including the core header. See
YOMM2_DEFAULT_POLICY
for more details.
<yorel/yomm2/symbols.hpp>
This header defines two macros: YOMM2_GENSYM
, which generates a new obfuscated
symbol each time that is is expanded; and YOMM2_SYMBOL(seed)
, which generates
an obfuscated symbol (the same symbol for the same value of seed
).
These macros are useful when using the core interface, which requires instantiating static objects to register classes, methods, and definitions; and for defining the “key” type for the method template.
<yorel/yomm2/templates.hpp>
This header defines experimental meta-programming constructs intended to facilitate the creation of templatized method and methods definitions. See the template tutorial for examples.
<yorel/yomm2/macros.hpp>
This header defines the upper-case versions of the macros (YOMM2_DECLARE
etc).
<yorel/yomm2/cute.hpp>
This header defines the lower-case versions of the macros (declare_method
etc).
<yorel/yomm2.hpp>
This was the recommended header before version 1.3.0. Includes
<yorel/yomm2/core.hpp>
and <yorel/yomm2/macros.hpp>
.
YOMM2 can be used as a header-only library. This is the recommended way. The runtime adds ~56K (~36K after stripping) when compiled with clang++-16 for the x86-64 architecture.
YOMM2 can also be installed as a shared library, by setting the cmake variable
YOMM2_SHARED
to ON
. The preprocessor symbol YOMM2_SHARED
must be defined
for the shared runtime to be used.
Name | Kind | Purpose |
---|---|---|
class_declaration | class template | declare a class and its bases |
declare_method | macro | declare a method |
declare_static_method | macro | declare a static method inside a class |
default_policy | typedef | debug or release , depending on NDEBUG |
define_method | macro | add a definition to a method |
define_method_inline | macro | add an definition to a method in a container, and make it inline |
error | class | base class of error subclasses |
error_handler_type | type | handler function |
error_type | variant | object passed to error handler |
friend_method | macro | make a method in a container, or the entire container, a friend |
generator | class | generate compile-time offsets, pre-calculate dispatch data |
hash_search_error | class | failure to find a hash function for registered classes |
make_virtual_shared | function template | create an object and return a virtual_shared_ptr |
method | class template | implement a method |
method_call_error | class | information about a failed method call |
method_call_error_handler | type | type of a function called when a method call fails |
method_class | macro | get method class from method signature |
method_container | macro | declare a method definition container |
method_definition | macro | retrieve a definition from a container |
method_table_error | class | virtual_ptr static type differs from dynamic type |
policy | namespace | contains policy and facet related mechanisms |
basic_error_output | class template | generic implementation of error_output |
basic_policy | class template | create a policy |
basic_trace_output | class template | generic implementation of trace_output |
checked_perfect_hash | class template | implementation of type_hash using a perfect hash, with runtime checks |
debug | class | most versatile policy, with runtime checks |
deferred_static_rtti | class | facet sub-category: do not collect type ids at static contstruction time |
error_handler | class | facet responsible for handling errors |
error_output | class | facet responsible for printing errors |
external_vptr | class | sub-category of vptr_placement ; vptrs are stored out of objects |
fast_perfect_hash | class template | implementation of type_hash using a fast, perfect hash |
minimal_rtti | class | implementation of rtti that des not use RTTI |
release | class | fastest and most versatile policy, no runtime checks |
rtti | class | facet responsible fro RTTI |
std_rtti | class | implement rtti facet using standard RTTI |
throw_error | class | handle errors by throwing exceptions |
trace_output | class template | facet responsible for tracing internal operations |
type_hash | class | facet responsible for hashing type ids |
vectored_error | class template | handle errors by calling a std::function |
vptr_map | class template | implement facet vptr_placement using a std::unordered_map |
vptr_placement | class | facet responsible for finding the vptr for an object |
vptr_vector | class template | implement facet vptr_placement using a std::vector |
register_class | macro | register a class and its bases (deprecated) |
register_classes | macro | register classes and their inheritance relationships |
resolution_error | class | method call does not resolve to exactly one definition |
RestrictedOutputStream | concept | std::ostream -like class with just a few operations |
set_error_handler | function | set the function called for all errors |
set_method_call_error_handler | function | set function to call when a method call fails |
type_id | typedef | alias to std::uintptr_t , used for storing dispatch data |
unknown_class_error | class | class used in method declaration, definition, or call was not registered |
update | function | set up dispatch tables |
update_methods | function | set up dispatch tables (deprecated, requires linking with library) |
use_classes | class template | register classes and their inheritance relationships |
virtual_ | class template | mark a method parameter as virtual |
virtual_ptr | class template | fat pointer for optimal method dispatch |
virtual_shared_ptr | class template | virtual_ptr using a std::shared_ptr |
YOMM2_CLASS | macro | same as register_class (deprecated) |
YOMM2_CLASSES | macro | same as register_classes |
YOMM2_DECLARE | macro | same as declare_method |
YOMM2_DECLARE_METHOD_CONTAINER | macro | same as method_container |
YOMM2_DEFINE | macro | same as define_method |
YOMM2_DEFAULT_POLICY | macro | global default policy override |
YOMM2_DEFINE_INLINE | macro | same as define_method_inline |
YOMM2_DEFINITION | macro | same as method_definition |
YOMM2_FRIEND | macro | same as friend_method |
YOMM2_GENSYM | macro | generate a unique symbol |
YOMM2_METHOD_CLASS | macro | get method class from method signature |
YOMM2_STATIC | macro | instantiate an anonymous static object |
YOMM2_STATIC_DECLARE | macro | declare a static method inside a class |
YOMM2_SYMBOL | macro | generate an obfuscated symbol |
name | type | purpose |
---|---|---|
aggregate | class template | make a type by aggregating a set of types |
apply_product | meta-function | apply templates to the n-fold Cartesian product of types lists |
not_defined | meta-function | tell use_definitions to discard a definition |
product | meta-function | form n-fold Cartesian product of types lists |
template_ | class template | wrap a template in a type |
templates | class template | wrap templates in a types list |
types | class template | sequence of types |
use_definitions | class template | add batch of definitions from a generic container to methods |