yomm2

yorel::yomm2::method

defined in <yorel/yomm2/core.hpp>, also provided by <yorel/yomm2/keywords.hpp>

template<
    typename Key, typename ReturnType, typename... Args,
    class Policy = default_policy
>
struct method; // not defined

template<typename Key, typename ReturnType, typename... Args, class Policy>
struct method<Key, ReturnType(Args...), Policy>;

method provides a static function object, fn, that takes a list of arguments of type Args, minus the virtual_ decorator, and returns ReturnType. Method definitions can be added with the method::add_function and method::add_definition class templates.

Template parameters

Member functions

Name Description
constructor construct and register the method
destructor destruct and unregister the method
operator() call the method

constructor

method<Key, R(Args...)>::method();

Add the method to the policy’s method list.

destructor

method<Key, R(Args...)>::~method();

Remove the method from the policy’s method list.

call operator

method<Key, R(Args...)>::operator()(args...);

Call the method. The dynamic types of the arguments corresponding to a virtual_ parameter determine which method definition to call.

Static member variable

Name Description
fn function object to call the method

fn

method<Key, R(Args...)>::fn;

The single instance of method<Key, R(Args...)>. Used to call the method.

Member types

Name Description
add_function add a definition to the method
add_definition add a definition container to the method
next_type type of a pointer to the next most specialised definition
use_next CRTP base for definitions that use next

add_function

template<auto Function>
struct add_function {
    explicit add_function(next_type* next = nullptr);
};

Register Function as a definition of the method. If specified, next is set to a pointer to the next most specialised definition, or to an error handler if the next definition does not excist, or is ambiguous.

The parameters of Function must be compatible with the corresponding parameters in the method when virtual, and invariant otherwise. The return type of Function must be compatible with the return type of the method.

add_definition

template<typename Container>
struct add_definition {
    add_definition();
};

Register static member function Container::fn as a definition of the method. If static member variable Container::next exists, it is set to a pointer to the next most specialised definition, or to an error handler if the next definition does not exist, or is ambiguous.

The parameters of Container::fn must be compatible with the corresponding parameters in the method when virtual, and invariant otherwise. The return type of Function must be compatible with the return type of the method.

next_type

template<typename Key, typename R, typename... Args>
struct method<Key, R(Args...)> {
    using next_type = unspecified;
};

Register Function as a definition of the method. If specified, next is set to a pointer to the next most specialised definition, or to an error handler if the next definition does not excist, or is ambiguous.

The parameters of Function must be compatible with the corresponding parameters in the method when virtual, and invariant otherwise. The return type of Function must be compatible with the return type of the method.

use_next

template<typename Container>
struct use_next {
    static next_type next;
};
template<typename Key, typename R, typename... A, typename... Unspecified>
template<typename Container>
typename method<Key, R(A...), Unspecified...>::next_type
method<Key, R(A...), Unspecified...>::use_next<Container>::next;

CRTP base class for definition containers that need to call the next most specialised method.

Static member variables must be declared inside the class definition, and defined outside of it. This is cumbersome. use_next declares, and defines, a static next function pointer, which can be injected in the container’s scope via inheritance, to be picked up by add_container. If this doesn’t make sense, see the example below.

Example

#include <yorel/yomm2/core.hpp>
#include <yorel/yomm2/symbols.hpp> // for YOMM2_GENSYM

#include <memory>
#include <string>

struct Animal { virtual ~Animal() {} };
struct Cat : Animal {};
struct Dog : Animal {};
struct Bulldog : Dog {};

namespace yomm2 = yorel::yomm2; // for brevity
using yomm2::virtual_;

YOMM2_STATIC(yomm2::use_classes<Animal, Cat, Dog, Bulldog>);

struct kick_methods;
using kick = yomm2::method<kick_methods, std::string(virtual_<Animal&>)>;

std::string kick_cat(Cat& dog) { return "hiss"; }
YOMM2_STATIC(kick::add_function<kick_cat>);

std::string kick_dog(Dog& dog) { return "bark"; }
YOMM2_STATIC(kick::add_function<kick_dog>);

struct kick_bulldog : kick::use_next<kick_bulldog> {
    static std::string fn(Bulldog& dog) { return next(dog) + " and bite"; }
};
YOMM2_STATIC(kick::add_definition<kick_bulldog>);

struct YOMM2_SYMBOL(pet); // use obfuscated name
using pet = yomm2::method<YOMM2_SYMBOL(pet), std::string(virtual_<Animal&>)>;

std::string pet_cat(Cat& dog) { return "purr"; }
YOMM2_STATIC(pet::add_function<pet_cat>);

std::string pet_dog(Dog& dog) { return "wag tail"; }
YOMM2_STATIC(pet::add_function<pet_dog>);

BOOST_AUTO_TEST_CASE(ref_method_example) {
    yomm2::update();

    std::unique_ptr<Animal>
        felix = std::make_unique<Cat>(),
        snoopy = std::make_unique<Dog>(),
        hector = std::make_unique<Bulldog>();

    BOOST_TEST(kick::fn(*felix) == "hiss");
    BOOST_TEST(kick::fn(*snoopy) == "bark");
    BOOST_TEST(kick::fn(*hector) == "bark and bite");

    BOOST_TEST(pet::fn(*felix) == "purr");
    BOOST_TEST(pet::fn(*snoopy) == "wag tail");
    BOOST_TEST(pet::fn(*hector) == "wag tail");
}