Skip to content
/ yarma Public

Yet Another Reflection Macro: simple, flexible reflection in C++17

Notifications You must be signed in to change notification settings

badair/yarma

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 

Repository files navigation

Yet Another Reflection Macro: simple, flexible reflection in C++17.

Yarma was designed for ease-of-use over performance, but it's not terribly slow either. Yarma depends on a working implementation of std::variant, Boost (for Boost.Preprocessor), and my own CallableTraits library, which is currently seeking a Boost review manager.

Once you have the dependencies installed, you only need a single header file, yarma.hpp. The YARMA_REFLECT macro simply defines a member function named "members" that returns an array of custom variant types, which can then be inspected.

#include <string>
#include <iostream>
#include "yarma.hpp"

using std::string;
using std::cout;
using std::visit;

struct employee {
    
    int id;
    string name;
    double hourly_wage;
    int weekly_hours;
    
    double weekly_earnings() const {
        return hourly_wage * weekly_hours;
    }
    
    // This macro does nothing more than define a "members" function
    YARMA_REFLECT(
        (id)
        (name)
        (hourly_wage)
        (weekly_hours)
        (weekly_earnings)
    )
};

int main () {
    
    auto emp = employee{1234, "John Doe", 7.25, 40};
    
    for (auto m : emp.members()) {
        
        cout << m.name() << " = ";
        
        // We use std::visit here because the reflected members
        // are not convertible to each other. If they were, we
        // could simply call m.get(emp) instead. The get function
        // speaks std::invoke, so you can pass arguments to member
        // functions through it too, as long as your reflected members
        // have covariant signatures. If not, you can do your own
        // SFINAE magic in a visitor using decltype(mem)::parameter_types,
        // which aliases a std::tuple containing the member's std::invoke
        // signature (where the first element is a reference to the
        // parent object).You can also use decltype(mem)::return_type
        // to inspect the result of std::invoke without needing to
        // decltype it.
        visit([=](auto mem) { cout << mem.get(emp); }, m);
        
        // is_data returns true for data members
        if(m.is_data())
            cout << " (data) ";   
        else
            // arity returns -1 for data members
            cout << " (function taking " << m.arity() << " arguments) ";
        
        cout << '\n';
    }
}

output:

id = 1234 (data) 
name = John Doe (data) 
hourly_wage = 7.25 (data) 
weekly_hours = 40 (data) 
weekly_earnings = 290 (function taking 0 arguments) 

You can run this code using the "Try it online" button at the top of this readme. [badge.Wandbox]: https://img.shields.io/badge/try%20it-online-blue.svg

About

Yet Another Reflection Macro: simple, flexible reflection in C++17

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages