All Projects → badair → eraserface

badair / eraserface

Licence: other
dynamic polymorphism without inheritance

Programming Languages

C++
36643 projects - #6 most used programming language
CMake
9771 projects

Projects that are alternatives of or similar to eraserface

crypto3
Modern Cryptography Suite in C++17
Stars: ✭ 21 (-32.26%)
Mutual labels:  boost
atbuild
Use JavaScript to generate JavaScript
Stars: ✭ 26 (-16.13%)
Mutual labels:  preprocessor
mtxclient
Client API library for Matrix, built on top of Boost.Asio
Stars: ✭ 21 (-32.26%)
Mutual labels:  boost
FFmpegPlayer
Simple FFmpeg video player
Stars: ✭ 72 (+132.26%)
Mutual labels:  boost
malloy
A C++ library providing embeddable server & client components for both HTTP and WebSocket.
Stars: ✭ 29 (-6.45%)
Mutual labels:  boost
ts-c99-compiler
ANSI C 16bit Compiler + NASM Assembler + Intel 8086 / 80186 + X87 emulator written entirely in TypeScript
Stars: ✭ 78 (+151.61%)
Mutual labels:  preprocessor
preprocessor-loader
Bring the awesome "Conditional Compilation" to the Webpack, and more.
Stars: ✭ 32 (+3.23%)
Mutual labels:  preprocessor
static string
A fixed capacity dynamically sized string
Stars: ✭ 46 (+48.39%)
Mutual labels:  boost
markedpp
Preprocessor for markdown files
Stars: ✭ 21 (-32.26%)
Mutual labels:  preprocessor
svelte-style-directive
A custom Svelte preprocessor to add support for style directive.
Stars: ✭ 19 (-38.71%)
Mutual labels:  preprocessor
getboost
NuGet packages for Boost framework.
Stars: ✭ 49 (+58.06%)
Mutual labels:  boost
pre-class-accessors
No description or website provided.
Stars: ✭ 12 (-61.29%)
Mutual labels:  preprocessor
boost beast websocket echo
A collection of Demo applications to try to help you understand how Asio and Beast work
Stars: ✭ 12 (-61.29%)
Mutual labels:  boost
concurrent-resource
A header-only C++ library that allows easily creating thread-safe, concurrency friendly resources.
Stars: ✭ 17 (-45.16%)
Mutual labels:  boost
zork
Full C++-17 port of the 616-point version of Zork from MIT circa 1978-1981
Stars: ✭ 16 (-48.39%)
Mutual labels:  boost
rollup-plugin-jscc
Conditional compilation and compile-time variable replacement for Rollup
Stars: ✭ 52 (+67.74%)
Mutual labels:  preprocessor
commonpp
Small library helping you with basic stuff like getting metrics out of your code, thread naming, etc.
Stars: ✭ 29 (-6.45%)
Mutual labels:  boost
asio-extensions
Additional functionality built on top of (Boost.)Asio
Stars: ✭ 16 (-48.39%)
Mutual labels:  boost
CDT-plusplus
Causal Dynamical Triangulations in C++ using CGAL
Stars: ✭ 49 (+58.06%)
Mutual labels:  boost
scelta
(experimental) Syntactic sugar for variant and optional types.
Stars: ✭ 140 (+351.61%)
Mutual labels:  boost

Eraserface

Type-erased polymorphic interfaces

Note: This project is based on the Boost.FunctionTypes interface example by Tobias Schwinger.

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.

Interfaces are a prominent feature in many object-oriented programming languages, such as Java. Historically, an "interface" in C++ is modeled by a pure abstract base class. However, the inheritance-based approach to interfaces has the following drawbacks:

  • Inheritance-based interfaces require that all interface functions be virtual.
    • A function that calls another function of the interface must do so via virtual dispatch, and may not be inlined.
  • A derived class cannot implement an interface function via function template.
  • Inheritance-based interfaces are intrusive
    • The memory layout of an interface-derived object is altered and obscured:
      • A vtable pointer must be stored, even for objects used in code where virtual lookup is not necessary
      • interface-derived objects cannot be standard layout types, by definition
      • Interfaces can only be applied to classes which can be modified by the programmer
      • Adding an interface requires all clients to be rebuilt
  • Inheritance-based interfaces are a source of tighter coupling - an interface needed for one small section of code must be inherited by a class that might be used in many unrelated sections of code

Fortunately, it is possible to mitigate some or all of these drawbacks by using an alternative approach based on type erasure. Eraserface is an implementation of this approach using template metaprogramming and preprocessor metaprogramming techniques.

Usage

Eraserface is contained to a single header file:

    #include <eraserface/eraserface.hpp>

The DEFINE_ERASERFACE macro generates a type-erased interface type which can be used to apply an interface to an object, without altering class definitions. This allows objects to be interfaced polymorphically whose class definitions are not accessible to the programmer. In addition, the presence of implementations are checked and enforced at compile time, so there is no safety disadvantage to using this technique. Eraserface even accounts for member data, such as some_data below:

    DEFINE_ERASERFACE( my_interface,
      (( a_func, void(int) const ))
      (( another_func, int() ))
      (( some_data, int ))
    );

This macro will generate an interface that roughly corresponds to the following abstract base class:

    struct my_interface {
        virtual void a_func(int) const = 0;
        virtual int another_func() = 0;

        //(imagine a virtual data member, accessible with a function call)
        virtual int some_data;
    };

The difference is that an Eraserface interface is applied "inline", instead of at a class definition :

    my_interface i = some_object;

Caveats

First and foremost, Eraserface is a fun metaprogramming exercise. A handful of test cases exist in this repository, which one should review (and perhaps expand) before deciding to use Eraserface in their own project.

Eraserface requires access to member function pointers through the target object type. This brings 4 important considerations:

  • Publicly inherited member functions cannot be used to implement an Eraserface interface, unless they are imported with using declarations in the derived class.
  • Neither covariance nor contravariance are supported.
  • objects of classes in the std namespace may not be used, since taking the address of a member function of a class in this namespace is undefined behavior.
  • If interface members are implemented with a member function template, Eraserface will instantiate the template and ODR-use the member function according to the respective signature(s) passed to the DEFINE_ERASERFACE macro.

The Eraserface macro adds two names to the current scope. The first macro parameter (e.g. my_interface in the previous example) is expanded to a struct. The first macro parameter is also appended with _detail_, which is a class in the current scope (e.g. my_interface_detail_ in the previous example).

Dependencies

Dependencies must be available in the include path.

Compatibility

Eraserface worked at some point on GCC 4.9.3+ and Clang 3.8+, and maybe it still does. I need to set up continous integration tests. MSVC is not supported, largely (if not entirely) due to name-lookup compiler bugs.

License

Distributed under the Boost Software License, Version 1.0.

  • (C) Copyright Tobias Schwinger
  • (C) Copyright 2016, 2017 Barrett Adair
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].