Git Product home page Git Product logo

veselink1 / refl-cpp Goto Github PK

View Code? Open in Web Editor NEW
1.0K 30.0 74.0 4.23 MB

Static reflection for C++17 (compile-time enumeration, attributes, proxies, overloads, template functions, metaprogramming).

Home Page: https://veselink1.github.io/refl-cpp/md__introduction.html

License: MIT License

C++ 98.45% CMake 1.55%
cpp metaprogramming refl-cpp reflection header-only cpp17 no-dependencies production-ready

refl-cpp's Introduction

Hi there πŸŽ‡

About me πŸ‘©β€πŸ’»

All you need to know is:

  • I'm a Software Engineer πŸ’»
  • I'm based in Manchester πŸ“Œ
  • I work at Couchbase

Highlights ✨

  • refl-cpp - Compile-time reflection for C++17
  • FancyWM - Tiling Window Manager for Windows 10/11
  • elfshaker - Object Code VCS written in Rust

Let's Connect πŸ“«

refl-cpp's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

refl-cpp's Issues

Is there a possibility of adding features like Boost.PFR?

Hi, thank you for providing this great library.

The API of this project is very good, but the requirement of using macros is not ideal. There are some abilities to do reflection without macros, and they are used by Boost.PFR and magic_enum.

Have you looked into using these approaches to remove the need for calling macros in your library?

Thanks!

Is there any way to recusively traverse a type or support std type traits?

I'm working on a comprehensive serializer which has to support a couple of scenarios, such as

  • nested types
  • stl containers
  • dynamic types / inheriting
    I was experimenting with this library if it could be used to replace a lot of extra overhead including the serialization. However, I've found no way to apply stl type traits to determine if a member is either a pointer or a class (struct) or something else (using my own type traits).

I'm using the following example code below:

struct serializable : refl::attr::usage::field, refl::attr::usage::function
{
};

template <typename T> void serialize(std::ostream & os, T && value)
{
	// iterate over the members of T
	for_each(refl::reflect(value).members, [&](auto member) {
		// is_readable checks if the member is a non-const field
		// or a 0-arg const-qualified function marked with property attribute

		if constexpr (is_readable(member) && refl::descriptor::has_attribute<serializable>(member))
		{

			if constexpr (std::is_class_v<decltype(member(value))>) // This is always false
			{
				os << get_display_name(member) << "= {\n";
				serialize(os, member(value)); // This always warns for resuesion
				os << "}\n";
			}
			else
			{
				os << get_display_name(member) << "=";
				os << member(value) << ";"; // This always fails 
			}
		}
	});
}

struct Point
{
	float x;
	float y;
	[[nodiscard]] float magnitude() const { return std::sqrt(x * x + y * y); }
};

REFL_TYPE(Point, bases<>)
REFL_FIELD(x, serializable())
REFL_FIELD(y, serializable())
REFL_FUNC(magnitude)
REFL_END

struct Line
{
	Point start;
	Point end;
	[[nodiscard]] float length() const { return Point({ end.x - start.x, end.y - start.y }).magnitude(); }
};

REFL_TYPE(Line, bases<>)
REFL_FIELD(start, serializable())
REFL_FIELD(end, serializable())
REFL_FUNC(length)
REFL_END

TEST(Reflection, HelloTest)
{
	std::cout << "Custom serialization: ";
	serialize(std::cout, Point{ 1, 1 });

	serialize(std::cout, Line{ { 1, 1 }, { 2, 2 } });
	std::cout << std::endl;

	SUCCEED();
}

I'd like to use it in more complex scenarios like this. Is there any legitimate way to do this?

Q: make REFL_AUTO, REFL_TYPE etc. callable from nested namespace

Hi @veselink1,
thanks again for time and making refl-cpp public! We gained quite a bit more experience with your library and are happily using it for (de-)serialisation in our little lib.

From a usability point of view: what would it take to make REFL_TYPE callable from a nested namespace?

In the documentation you correctly pointed out that the macros need to be called from within the global namespace.
This becomes a bit unwieldy, a potential source of errors, and less readable in larger and/or structured projects where the structs are declared inside nested namespaces, e.g.:

namespace other_a {
namespace other_b {

struct Point {
  float x;
  float y;
  float z;
};
// REFL_AUTO(type(Point), field(x), field(y), field(z)) // <- would like to define it here

// [..] many unrelated lines of code [..]

} // namespace other_a
} // namespace other_b

REFL_AUTO(type(Point), field(x), field(y), field(z)) // <- have to define it here (global namespace)

Ideally one would like to declare the visitor macros right after the structs have been declared to minimise synchronisation errors.
Any idea how this could be extended (other than closing/reopening the other namespaces)? Any help would be much appreciated!

Season greetings and wish you a successful New Year 2022! πŸŽ„ 🎁 πŸŽ‰

Don't build on Windows 10 in VS 2017 version 15.9.26

1>c:\source\repos\testtest_0\testtest_0\refl.hpp(1383): error C2672: 'refl::trait::detail::index_of_instance': no matching overloaded function found
1>c:\source\repos\testtest_0\testtest_0\refl.hpp(1385): note: see reference to class template instantiation 'refl::trait::index_of_instance<T,refl::util::type_list<Ts...>>' being compiled
1>c:\source\repos\testtest_0\testtest_0\refl.hpp(1383): error C3207: 'refl::trait::detail::index_of_instance': invalid template argument for 'T', class template expected
1>c:\source\repos\testtest_0\testtest_0\refl.hpp(1326): note: see declaration of 'refl::trait::detail::index_of_instance'

Question about tuple things and bindings

Hello i try to use refl-hpp instead of my own reflection library

For registering into a scripting type system using reflection i was using the following snippet

 template <typename ...Ts>
 using meta::map = std::tuple<Ts...>;

struct transform_2d
    {
        transform_2d() noexcept = default;

        transform_2d(float x_,
                     float y_, float width_, float height_, float scale_x_, float scale_y_,
                     float angle_) noexcept :
            x(x_),
            y(y_),
            width(width_),
            height(height_),
            scale_x(scale_x_),
            scale_y(scale_y_),
            angle(angle_),
            original_x(x_)
        {
        }

        float x{0.0f}; //!< x
        float y{0.0f}; //!< y
        float width{0.0f};
        float height{0.0f};
        float scale_x{1.0f};
        float scale_y{1.0f};
        float angle{0.0f};
        bool rotating{false};

        //! Original (mutable because of EnTT, (should not be modified))
        mutable float original_x{x};
        mutable float original_y{y};
        mutable float original_width{width};
        mutable float original_height{height};

        reflect_class(transform_2d)

        static constexpr auto reflected_functions() noexcept
        {
            return meta::makeMap();
        }

        static constexpr auto reflected_members() noexcept
        {
            return meta::makeMap(reflect_member(&transform_2d::y),
                                 reflect_member(&transform_2d::x),
                                 reflect_member(&transform_2d::width),
                                 reflect_member(&transform_2d::height),
                                 reflect_member(&transform_2d::scale_x),
                                 reflect_member(&transform_2d::scale_y),
                                 reflect_member(&transform_2d::angle),
                                 reflect_member(&transform_2d::rotating));
        }
    };


 template <typename T>
    void register_type(sol::state &state, shiva::logging::logger logger) noexcept
    {
        const auto table = std::tuple_cat(
            std::make_tuple(T::class_name()),
            T::reflected_functions(),
            T::reflected_members());

        try {
            std::apply(
                [&state](auto &&...params) {
                    state.new_usertype<T>(std::forward<decltype(params)>(params)...);
                }, table);
        }
        catch (const std::exception &error) {
            logger->error("error: {}", error.what());
            return;
        }

        logger->info("successfully registering type: {}", T::class_name());
    }


register_type<transform2d>();

It"s was generating a snippet like:

new_usertype<transform_2d>("transform_2d",
		"x", &my_class::x,
		"y", &my_class::y); /

Is it possible using your lib ?

Is there a way to reflect private fields?

A bit of newbie question I guess. With the current status of C++, are there any ways we can reflect on private member fields or methods?

My main use case is de-serialization and populate class private fields from a parser. What's the best approach if reflection is not possible? I'm willing to friend or expose to a particular builder but not public the whole data section. Thanks.

Usage help

I just came across this library and I must admit that it's bit too complex for an average user. Nevertheless, i appreciate the immense amount of work into it.
I have a particular requirement that brought me here and i would like to know how to achieve them if that is possible.

  1. Is there an equivalent of offsetof(struct, member) and sizeof(member)? My use case requires me to read and write the whole structure or portions of it as a bytestream. This can be achieved with something like...
    memcpy(buffer, &myStructAsByteStream[offsetof(mystruct, member)], bytesToSend)

2)Is there a way to get the index of a member of the struct?
3) Is there a way to get the member from index? This is the inverse of the previous.

Multiple definition of `refl::runtime::detail::next_depth(int)'

When including refl.hpp from more than one source file using gcc 7.5.0, the compiler complains that refl::runtime::detail::next_depth(int) is defined multiple times.

g++ -I./src -MMD -MP --std=c++17 -c src/Effect.cpp -o build/./src/Effect.cpp.o
g++ -I./src -MMD -MP --std=c++17 -c src/main.cpp -o build/./src/main.cpp.o
g++ -I./src -MMD -MP --std=c++17 -c src/Object.cpp -o build/./src/Object.cpp.o
g++ ./build/./src/Effect.cpp.o ./build/./src/main.cpp.o ./build/./src/Object.cpp.o -o build/a.out
./build/./src/main.cpp.o: In function `refl::runtime::detail::next_depth(int)':
main.cpp:(.text+0x0): multiple definition of `refl::runtime::detail::next_depth(int)'
./build/./src/Effect.cpp.o:Effect.cpp:(.text+0x0): first defined here
./build/./src/Object.cpp.o: In function `refl::runtime::detail::next_depth(int)':
Object.cpp:(.text+0x0): multiple definition of `refl::runtime::detail::next_depth(int)'
./build/./src/Effect.cpp.o:Effect.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
Makefile:17: recipe for target 'build/a.out' failed
make: *** [build/a.out] Error 1

Moving the function into an anonymous namespace or declaring it static (both of which force internal linkage) resolves the issue.

100-item limit for REFL_AUTO

EDIT:

I figured out that refl-cpp can already handle >100 items. You just have to use the other syntax:

REFL_TYPE(MyType)
   REFL_FUNC(Func1)
   ...
   REFL_FUNC(Func193)
REFL_END

As far as I can tell, this syntax works identically to REFL_AUTO including support for user-defined properties. So my original enhancement request was moot. I'm leaving the rest of this issue here in case any other lost lamb comes looking for help with it. It would be helpful to call it out in the documentation as an alternative when there are >100 items in the REFL_AUTO list.

(Original text follows.)

=============================

I'm working with a pre-existing class framework that is risky to modify. I am finding myself exceeding or near-exceeding the 100-item limit in REFL-AUTO. Fine, I thought to myself, I'll just expand it to 200 in a fork. But then I hit an absurdly laughable limit in the Visual Studio 2019 compiler. It absolutely cannot and will not handle a macro with more than 127 arguments.

It would be nice if there were a way to continue REFL_AUTO for a class in a subsequent macro. I don't understand the refl-cpp code well enough to suggest a sensible syntax, but I'm thinking something along the lines of

/* fantasy syntax: see edit above. This makes no sense based on that edit, but it was my original post. */

REFL_AUTO
(
   type(mytype, continues()),
   func(func1),
   ...
   func(func99)
)

REFL_CONTINUES
(
   type(mytype),   // plus, ideally, the option to continue again with continues()
   func(func101),
   ...
)

Is there a way to access member type name?

Is there a way to do something like this pseudo-code? I tried to read doc and code, but did not find.

for_each(refl::reflect(x).members, [&](auto member) {
	if constexpr (std::is_same<member.type, bool>) { // or member.typename == "bool"
		std::cout << "bool " << member.name << " = " << (member(x) ? "true" : "false") << ";";
	}
});

Q: how to reflect on member functions' parameters and return types?

We are using refl-cpp primarily for reflections on member fields which works perfectly fine for our use case.

We may have a new application now, where I was wondering whether this could be also extended also to member functions, notably to retrieve their parameter and return type signatures during compile time.

For example, having the following demo class definition:

class Circle {
    double r;
public:
    Circle(double val) : r(val) {}
    double getRadius() const { return r; }
    void setRadius(double radius) { r = radius; }
    std::string getFunc(int a, double b, std::string c) const { return fmt::format("{}{}{}",a,b,c); }
    double getDiameter() const { return 2 * r; }
    double getArea() const { return M_PI * r * r; }
};

How would one go about retrieving the setRadius(double) calling parameter (double) and return value (void)? Or, more generally, the number of calling parameters of getFunc(...) which would be std::tuple<int,double,std::string> and its return type std::string?

There is an example that illustrates how to get the function pointer and how to call 'std::invoke(..)` but this seems to implicitly assume the calling parameter and return types:

using refl::reflect;
using refl::util::find_one;
constexpr auto type = reflect<Circle>();
 
constexpr auto func = find_one(type.members, [](auto m) { return m.name == "getRadius"; }); // -> function_descriptor<Circle, 0>{...}

func.name; // -> const_string<6>{"getRadius"}
func.attributes; // -> std::tuple<>{}
func.is_resolved; // -> true
func.pointer; // -> pointer of type double (Circle::* const)()
 
using radius_t = double (Circle::* const)();
func.template resolve<radius_t>; // -> pointer of type radius_t on success, nullptr_t on fail.
 
Circle c(2.0);
func.invoke(c); // -> the result of c.getRadius()

Also more generally, how would one register, find and call the different class constructors and parameter signatures?

This (potentially new) functionality has applications in GUIs and other areas where the compile/run-time definitions are driven by configuration files.

Any help, suggestions, or feedback would be welcome. Thanks in advance.

Error when compiling (type_info__<T*> has name defined as char[N] instead of const_string<N>)

Hello,

When I try to compile my project in Visual Studio 2019 with the refl.hpp file, I get the following error:

'initializing': cannot convert from 'const char[2]' to 'const char[1]' on line 2154

I'm not an expert with the c++ preprocessor, so I don't know exactly where the problem is located in refl.hpp. Is this a bug? Or am I missing a preprocessor define to make it work? I am compiling with stdc++17.

Thanks,

Sander

Reflecting const/non const function overloads

Hi!

I got an class

class X{};

class A{
public:
  X& foo();
  const X& foo() const;
};

And I want to bind it to couple of script languages (chaiscript, python) and I need information about constness of given method for example pybind handles it by adding an additional tag

struct Widget {
    int foo(int x, float y);
    int foo(int x, float y) const;
};

py::class_<Widget>(m, "Widget")
   .def("foo_mutable", py::overload_cast<int, float>(&Widget::foo))
   .def("foo_const",   py::overload_cast<int, float>(&Widget::foo, py::const_));

How to properly reflect those methods using refl-cpp library?

Fix warnings for strict variadic macro checks (stronger C++20 enforcement)

While code-base spring cleaning I noticed that I (unwisely) ignored some refl-cpp variadic macro warnings that prevent gcc|clang compiling with more strict checks enabled (i.e. -Werror).

This shows up already for C++17 with the existing basic refl-cpp's default serialiser example and -pedantic compiler flags.
The corresponding sample output and warnings from running the tests at compiler-explorer:

  • gcc 10.2 or newer produces the following warning:
https://raw.githubusercontent.com/veselink1/refl-cpp/master/include/refl.hpp:4363:31: warning: ISO C++11 requires at least one argument for the "..." in a variadic macro
  • clang 12.0 or newer produce a bit more understandable warning outputs:
https://raw.githubusercontent.com/veselink1/refl-cpp/master/include/refl.hpp:4363:5: warning: must specify at least one argument for '...' parameter of variadic macro [-Wgnu-zero-variadic-macro-arguments]
    REFL_DETAIL_PRIMITIVE(char);
    ^
https://raw.githubusercontent.com/veselink1/refl-cpp/master/include/refl.hpp:4359:23: note: expanded from macro 'REFL_DETAIL_PRIMITIVE'
    REFL_TYPE(TypeName) \
                      ^

These checks seem to become more enforced for but also there seems to be a clean solution for C++20 #define FOO(x, ...) bar(x __VA_OPT__(,) __VA_ARGS__) as, for example, discussed in more detail here.
I was wondering whether this could be addressed under the premise that refl-cpp is C++17-based?

Any help would be much appreciated! Thanks in advance!

Another Compiler error on Visual Studio 2019 but not on XCode (GCC)

This is a followup to issue #52. If that issue is resolved (by applying the change in pull request #53), then this problem arises. For some reason, the compiler is unhappy with any kind of capture in the nested lamda. As mentioned in the title, this code compiles and runs correctly on XCode/GCC.

struct foo {
   int _bar;
   int get_bar() const {return _bar;}
   void set_bar(int val) {_bar = val;}
};
REFL_AUTO
(
   type(foo),
   func(get_bar, property()),
   func(set_bar, property())
)
template<class T>
static void ProcessClass()
{
   constexpr auto type = refl::reflect<T>();
   constexpr auto members = get_members(type);

   for_each(members, [&](auto member)
   {
      if constexpr (refl::descriptor::is_property(member) && !refl::descriptor::is_writable(member))
      {
         constexpr auto propertyName = refl::descriptor::get_display_name_const(member);
         constexpr auto setters = filter(get_members(refl::reflect<T>()), [&propertyName](auto chkMember) {
            if constexpr (!refl::descriptor::is_property(chkMember) || !refl::descriptor::is_writable(chkMember))
               return false;
            constexpr auto candidateName = refl::descriptor::get_display_name_const(chkMember);
            // This line generates C2131 expression did not evaluate to a constant (in Visual Studio 2019)
            // Comment it out and the code compiles
            if constexpr (propertyName == candidateName) return true;
            return false;
            });
      }
   });
}
static void my_runtime_func()
{
   ProcessClass<foo>();
}

The full error log is here:

1>C:\myprogram\myprogram.cpp(160,40): error C2131: expression did not evaluate to a constant
1>C:\myprogram\myprogram.cpp(160,27): message : failure was caused by a read of a variable outside its lifetime
1>C:\myprogram\myprogram.cpp(160,27): message : see usage of 'this'
1>C:\myprogram\refl-cpp\include\refl.hpp(1717): message : see reference to function template instantiation 'bool ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::()::<lambda_801970fce95e405cd618ce27f4e8933b>::operator ()<T>(T) const' being compiled
1>        with
1>        [
1>            T=refl::descriptor::function_descriptor<foo,0>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1717): message : see reference to function template instantiation 'auto refl::util::detail::filter<_Ty,refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>,>(F,refl::util::type_list<refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>,refl::util::type_list<>)' being compiled
1>        with
1>        [
1>            _Ty=ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::()::<lambda_801970fce95e405cd618ce27f4e8933b>,
1>            T=foo,
1>            F=ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::()::<lambda_801970fce95e405cd618ce27f4e8933b>
1>        ]
1>C:\myprogram\myprogram.cpp(162): message : see reference to function template instantiation 'auto refl::util::filter<ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::()::<lambda_801970fce95e405cd618ce27f4e8933b>,refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>(refl::util::type_list<refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>,F &&)' being compiled
1>        with
1>        [
1>            T=foo,
1>            F=ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::()::<lambda_801970fce95e405cd618ce27f4e8933b>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1558): message : see reference to function template instantiation 'auto ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::operator ()<_Ty>(_Ty) const' being compiled
1>        with
1>        [
1>            _Ty=refl::descriptor::function_descriptor<foo,0>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1552): message : see reference to function template instantiation 'auto refl::util::for_each::<lambda_5c0b9afd85e1cd59706d82c574cf7bd5>::operator ()<_Ty>(_Ty &&,size_t) const' being compiled
1>        with
1>        [
1>            _Ty=refl::descriptor::function_descriptor<foo,0>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1602): message : see reference to function template instantiation 'auto refl::util::detail::eval_in_order_to_tuple<_Ty,refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>,0,1,>(refl::util::type_list<refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>,std::integer_sequence<size_t,0,1>,F &&)' being compiled
1>        with
1>        [
1>            _Ty=refl::util::for_each::<lambda_5c0b9afd85e1cd59706d82c574cf7bd5>,
1>            T=foo,
1>            F=refl::util::for_each::<lambda_5c0b9afd85e1cd59706d82c574cf7bd5>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1635): message : see reference to function template instantiation 'auto refl::util::map_to_tuple<refl::util::for_each::<lambda_5c0b9afd85e1cd59706d82c574cf7bd5>,refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>(refl::util::type_list<refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>,F &&)' being compiled
1>        with
1>        [
1>            T=foo,
1>            F=refl::util::for_each::<lambda_5c0b9afd85e1cd59706d82c574cf7bd5>
1>        ]
1>C:\myprogram\myprogram.cpp(164): message : see reference to function template instantiation 'void refl::util::for_each<ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>,refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>(refl::util::type_list<refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>,F &&)' being compiled
1>        with
1>        [
1>            T=foo,
1>            F=ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>
1>        ]
1>C:\myprogram\myprogram.cpp(168): message : see reference to function template instantiation 'void ProcessClass<foo>(void)' being compiled
1>C:\myprogram\refl-cpp\include\refl.hpp(1695,32): error C2131: expression did not evaluate to a constant
1>C:\myprogram\refl-cpp\include\refl.hpp(1695,32): message : failure was caused by call of undefined function or one not declared 'constexpr'
1>C:\myprogram\refl-cpp\include\refl.hpp(1695,32): message : see usage of 'ProcessClass::<lambda_af8933d7cd3ab0757801f626deb33919>::()::<lambda_801970fce95e405cd618ce27f4e8933b>::operator ()'
1>C:\myprogram\refl-cpp\include\refl.hpp(1693,13): error C3487: 'refl::util::type_list<>': all return expressions must deduce to the same type: previously it was 'refl::util::type_list<refl::descriptor::function_descriptor<T,1>>'
1>        with
1>        [
1>            T=foo
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1699,34): error C2440: 'return': cannot convert from 'refl::util::type_list<>' to 'refl::util::type_list<refl::descriptor::function_descriptor<T,1>>'
1>        with
1>        [
1>            T=foo
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1699,34): message : No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

Add support to refl::runtime::debug for std::string_view

refl::runtime::debug interprets std::string_view as a char container and prints it in the form ['a', 'b', 'c'], instead of the more intuitive "abc". This is due to lacking reflection metadata for std::string_view and a check for begin() + end().

Feature: Support inherited members

Problem

refl-cpp does not automatically enumerate base types when using member_list<T> or type_descriptor<T>::members. This requires derived classes to redeclare members in their REFL_AUTO metadata definition for them to be properly picked up.

Solution

Use attr::base_types<Ts...> built-in attribute to generate a list of own and inherited members and expose that to the user. This will require there to be a distinction between the members declared by the current type and all the members of the type (incl. inherited).

Possible implementations

  1. Replace the current member_list (and type_descriptor::members) with the new combined list of members and expose the list of non-inherited members as declared_member_list and (and type_descriptor::declared_members). This might break compilation of code relying on util::find_one with a member name in case the same member is redeclared in the derived class metadata (as find_one static_asserts a single match). Can be solved by implementing "name shadowing" and hiding the inherited member.
  2. Keep the current contract intact, expose the new lists as ?_member_list (and type_descriptor::?_members). This might require users to remove duplicated members from derived class metadata, but also modify existing utility functions relying on those members to be in member_list.

example-serialize has 3 error

clang++ example-serialization.cpp -o example-serialization -std=c++17 -I ./../
In file included from example-serialization.cpp:10:
./../refl.hpp:1715:72: error: too few template arguments for class template 'debug'
struct is_instance_of<T, U<Args...>> : public std::is_same<T<Args...>, U<Args...>>
^
./../refl.hpp:1725:33: note: in instantiation of template class 'refl::trait::detail::is_instance_of<debug, refl::attr::base_types<> >' requested here
struct is_instance_of : detail::is_instance_of<T, U>
^
./../refl.hpp:1734:66: note: in instantiation of template class 'refl::trait::is_instance_of<debug, refl::attr::base_types<> >' requested here
[[maybe_unused]] static constexpr bool is_instance_of_v{ is_instance_of<T, U>::value };
^
./../refl.hpp:1899:42: note: in instantiation of variable template specializatio
How to solve the problem of serial compilation?I use g ++ to compile the same

Compiler error on Visual Studio 2019 but not on XCode (GCC)

I am trying to get some code working that processes properties. Part of what I need to do is, given a getter, to find the corresponding setter. My plan is to look for a writable property with the same friendly_name. If there is a more direct way to find the setter that matches a getter, I would not need to do this.

This code compiles and works on XCode/GCC. It produces a lot of errors (and eventually crashes) Visual Studio 2019. If it's a compiler bug, any suggestions for a workaround would be appreciated. If it's a bug in my code, I'd be very grateful to know how to fix it. The problem appears to be the call to get_display_name_const.

struct foo {
   int _bar;
   int get_bar() const {return _bar;}
   void set_bar(int val) {_bar = val;}
};
REFL_AUTO
(
   type(foo),
   func(get_bar, property()),
   func(set_bar, property())
)
template<class T>
static void ProcessClass()
{
   constexpr auto type = refl::reflect<T>();
   constexpr auto members = get_members(type);

   for_each(members, [&](auto member)
   {
      if constexpr (refl::descriptor::is_property(member) && ! refl::descriptor::is_writable(member))
      {
         // this line causes compile errors on Visual Studio 2019
         // comment it out and the program compiles without error   
         constexpr auto prop_name = refl::descriptor::get_display_name_const(member);
      }
   });
}
static void my_runtime_func()
{
   ProcessClass<foo>();
}

The errors look something like this:

1>C:\myprogram\refl-cpp\include\refl.hpp(207,49): error C2589: '(': illegal token on right side of '::'
1>C:\myprogram\refl-cpp\include\refl.hpp(3258): message : see reference to function template instantiation 'auto refl::util::const_string<7>::substr<0,3>(void) noexcept const' being compiled
1>C:\myprogram\refl-cpp\include\refl.hpp(3284): message : see reference to function template instantiation 'auto refl::descriptor::detail::normalize_accessor_name<T>(const T)' being compiled
1>        with
1>        [
1>            T=refl::descriptor::function_descriptor<foo,0>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(3335): message : see reference to function template instantiation 'auto refl::descriptor::detail::get_display_name<Descriptor>(const T) noexcept' being compiled
1>        with
1>        [
1>            Descriptor=refl::descriptor::function_descriptor<foo,0>,
1>            T=refl::descriptor::function_descriptor<foo,0>
1>        ]
1>C:\myprogram\-Source\myprogram.cpp(165): message : see reference to function template instantiation 'auto refl::descriptor::get_display_name_const<_Ty>(Descriptor) noexcept' being compiled
1>        with
1>        [
1>            _Ty=refl::descriptor::function_descriptor<foo,0>,
1>            Descriptor=refl::descriptor::function_descriptor<foo,0>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1557): message : see reference to function template instantiation 'auto ProcessClass::<lambda_b6ce6e654e3e0c33c3e1dc4678e74867>::operator ()<_Ty>(_Ty) const' being compiled
1>        with
1>        [
1>            _Ty=refl::descriptor::function_descriptor<foo,0>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1551): message : see reference to function template instantiation 'auto refl::util::for_each::<lambda_75c4d1b1bd375369e623ef71284a8c59>::operator ()<_Ty>(_Ty &&,size_t) const' being compiled
1>        with
1>        [
1>            _Ty=refl::descriptor::function_descriptor<foo,0>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1601): message : see reference to function template instantiation 'auto refl::util::detail::eval_in_order_to_tuple<_Ty,refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>,0,1,>(refl::util::type_list<refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>,std::integer_sequence<size_t,0,1>,F &&)' being compiled
1>        with
1>        [
1>            _Ty=refl::util::for_each::<lambda_75c4d1b1bd375369e623ef71284a8c59>,
1>            T=foo,
1>            F=refl::util::for_each::<lambda_75c4d1b1bd375369e623ef71284a8c59>
1>        ]
1>C:\myprogram\refl-cpp\include\refl.hpp(1634): message : see reference to function template instantiation 'auto refl::util::map_to_tuple<refl::util::for_each::<lambda_75c4d1b1bd375369e623ef71284a8c59>,refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>(refl::util::type_list<refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>,F &&)' being compiled
1>        with
1>        [
1>            T=foo,
1>            F=refl::util::for_each::<lambda_75c4d1b1bd375369e623ef71284a8c59>
1>        ]
1>C:\myprogram\-Source\myprogram.cpp(167): message : see reference to function template instantiation 'void refl::util::for_each<ProcessClass::<lambda_b6ce6e654e3e0c33c3e1dc4678e74867>,refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>(refl::util::type_list<refl::descriptor::function_descriptor<T,0>,refl::descriptor::function_descriptor<T,1>>,F &&)' being compiled
1>        with
1>        [
1>            T=foo,
1>            F=ProcessClass::<lambda_b6ce6e654e3e0c33c3e1dc4678e74867>
1>        ]
1>C:\myprogram\-Source\myprogram.cpp(171): message : see reference to function template instantiation 'void ProcessClass<foo>(void)' being compiled
1>C:\myprogram\refl-cpp\include\refl.hpp(207): error C2062: type 'unknown-type' unexpected
1>C:\myprogram\refl-cpp\include\refl.hpp(207,1): error C2059: syntax error: ')'
1>C:\myprogram\refl-cpp\include\refl.hpp(209,34): error C2131: expression did not evaluate to a constant
1>C:\myprogram\refl-cpp\include\refl.hpp(209,26): message : failure was caused by a read of an uninitialized symbol
1>C:\myprogram\refl-cpp\include\refl.hpp(209,26): message : see usage of 'NewSize'
1>C:\myprogram\refl-cpp\include\refl.hpp(211,28): error C3863: array type 'char [NewSize+1]' is not assignable
1>C:\myprogram\refl-cpp\include\refl.hpp(214,1): error C2971: 'refl::util::const_string': template parameter 'N': 'NewSize': a variable with non-static storage duration cannot be used as a non-type argument
1>C:\myprogram\refl-cpp\include\refl.hpp(127): message : see declaration of 'refl::util::const_string'
1>C:\myprogram\refl-cpp\include\refl.hpp(207): message : see declaration of 'NewSize'
1>C:\myprogram\refl-cpp\include\refl.hpp(214,1): fatal error C1903: unable to recover from previous error(s); stopping compilation
1>INTERNAL COMPILER ERROR in 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\HostX86\x64\CL.exe'
1>    Please choose the Technical Support command on the Visual C++
1>    Help menu, or open the Technical Support help file for more information

Is there a way to inspect enum cases?

Sorry to ask questions, I'm just having hard time reading the code, and trial and error is tough with meta-programming... Is there a way to list as strings the enum cases? Basic application would be auto-generating debug function that displays an enum as human-readable text.

Visual Studio 2017 code formatter breaks compilation for refl.hpp

Create a new C++ console application. Set warnings to level 4. Target latest. Build with the Visual Studio 2017 (v141) compiler:

Severity	Code	Description	Line	File	Project	Suppression State
Error	C2760	syntax error: unexpected token 'identifier', expected 'type specifier'	2563	..\refltestconsole\refl.hpp	ReflTestConsole	
Error	C2270	'MemberName_': modifiers not allowed on nonmember functions	2565	..\refltestconsole\refl.hpp	ReflTestConsole	
Error	C2995	'decltype(auto) MemberName_(Args &&...)': function template has already been defined	2568	..\refltestconsole\refl.hpp	ReflTestConsole	
Error	C2059	syntax error: '}'	2569	..\refltestconsole\refl.hpp	ReflTestConsole	
Error	C2143	syntax error: missing ';' before '}'	2569	..\refltestconsole\refl.hpp	ReflTestConsole	
Error	C2143	syntax error: missing ';' before '{'	2610	..\refltestconsole\refl.hpp	ReflTestConsole	
Error	C2447	'{': missing function header (old-style formal list?)	2610	..\refltestconsole\refl.hpp	ReflTestConsole	
Error	C2143	syntax error: missing ';' before 'namespace'	2771	..\refltestconsole\refl.hpp	ReflTestConsole	
Error	C1075	'{': no matching token found	2779	..\refltestconsole\refl.hpp	ReflTestConsole	

Q: smarter use of find_one or for_each for non-constexpr use-cases?

Hi,

I found some more time to delve into the details. Overall, this refl-cpp has a very smart design albeit it takes time to get used to the various (necessary) templates and paradigms. Actually, I am quite happy that my code became significantly more compact and type-safe(r) compared to previous incarnations.

I have a follow-up usability question: is there a smarter way to find and set (nested) field members based on run-time filter criteria and data while retaining the constexpr'-ness of the field's type` information?

For starters: I am aware of the binding example as well as earlier questions (issues) here and here that may or may not be related to this.

I wrote a MVP example to illustrate my specific problem/question of 'dynamically setting field variables based on external/run-time filter criteria and data' (see also compiler-explorer). N.B. here std::string fieldName is being used as a stand-in for the filter criteria but the real-world application also contains matching the field's member(value) type information etc:

#include <https://raw.githubusercontent.com/veselink1/refl-cpp/master/include/refl.hpp>
#include <iostream>
#include <fmt/format.h>

struct Point {
    int e0 = 1;
    int e1 = 2;
    int e2 = 3;
};
REFL_AUTO(type(Point),field(e0),field(e1),field(e2))

constexpr auto type = refl::reflect<Point>();

template<typename T>
int setField(const T& value, const std::string_view fieldName /* unused */) {
    constexpr auto field = refl::util::find_one(refl::reflect<T>().members, [&fieldName](auto m) { return m.name == "e0"; }); // N.B static field name
    // field(value) = ... ; // write data to member field (run-time)
    return field(value);
}

template<typename T>
int setField2(const T& value, const std::string_view fieldName) {
    auto field = refl::util::find_one(refl::reflect<T>().members, [&fieldName](auto m) { return m.name.str() == fieldName; }); // does not work/not constexpr
    //field(value) = ; // write data to member field (run-time)
    return field(value);
}

template<typename T>
int setField3(const T& value, const std::string_view fieldName) {
    int retValue = -1;
    refl::util::for_each(refl::reflect<T>().members, [&fieldName, &value, &retValue](auto field) {
            if (field.name.str() == fieldName) { // comparison OK but looping over each field              
                //field(value) = ; // write data to member field (run-time)
                retValue = field(value);
            }
    });
    
    return retValue;
}


int main(int argc, const char** argv) {
    Point a;
    const std::string fieldName = fmt::format("e{}", argc); // stand-in for dynamic data

    std::cout << "looking for " << fieldName << '\n';
    std::cout << setField(a, fieldName) << '\n'; // OK -- works but only for static field mappings
    // std::cout << setField2(a, fieldName) << '\n'; // does non work because of non-constexpr filter criteria
    std::cout << setField3(a, fieldName) << '\n'; // OK -- but loops through all member fields (ie. no early return)
}

The setField(..) function works well for field names (literals) that are known at compile-time but for our application, the fieldName is typically only known after having read some (dynamic) buffer.

The setField2(...) syntax using find_one(...) variant doesn't work for obvious reasons because the filter (presently) requires a constexpr matching condition which isn't possible in our case (ie. fieldNameand type are both dynamic run-time information).

The solution in the binding example seems to tackle this problem the other way round: first collect all dynamic information (from an xml-file) in a dynamic structure and then looping through all class fields and matching those with the correct filter parameter. In our case, we thought of retaining as much as possible of the constexpr'-ness of the class field information because -- preserving the type` information is very hard (and you solved this very well) -- and the idea was that looping through a constexpr map/info tree and filling the dynamic information immediately is much faster (i.e. doing the memory copy only once to its final destination) rather than allocating/storing all data in a temporary data structure and then to match the info to the constexpr field structure (i.e. doing the memory copy twice).

The setField3(...) function seems to be a viable workaround (solution?) under these conditions but the setField3(..) still feels a bit clumsy. Is there possibly a better/smarter option than this? constexpr field/method iterators? Is looping through all member fields for classes with ~20-30 (possibly nested) expensive?

Also -- possibly related to for_each and run-time conditions: are the static_asserts for example here and here really necessary and/or possibly too restrictive? What are they protecting against? N.B. I had some code which -- by by-passing these -- still seems to work fine. The issue seems to be primarily related to operator<< overloading and std::ostream within a for_each loop.

Any help, info, or suggestions would be much appreciated!

N.B. we are counting on that gcc and clang will soon also provide [C++20 constexpr compile-time implementations](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0980r1.pdf) of 'std::string' similarly to the latest MSVC -- albeit this won't change much for the above case).

get_bases has 4 error

clang++ myinheritance.cpp -o myinheritance -std=c++17
In file included from myinheritance.cpp:2:
./../refl.hpp:2231:37: error: static_assert expression is not an integral constant expression
static_assert(has_bases(t), "Target type does not have a bases<A, B, ...> attribute.");
~~~~~~~~~~^~
myinheritance.cpp:30:28: note: in instantiation of function template specialization 'refl::descriptor::get_bases<refl::descriptor::type_descriptor >' requested here
constexpr auto bases = get_bases(type);
^
myinheritance.cpp:51:5: note: in instantiation of function template specialization 'print_bases' requested here
print_bases();
^
In file included from myinheritance.cpp:2:
./../refl.hpp:2233:68: error: constexpr variable 'bases' must be initialized by a constant expression
constexpr auto bases = get_attributeattr::base_types(t);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
./../refl.hpp:2231:37: error: static_assert expression is not an integral constant expression
static_assert(has_bases(t), "Target type does not have a bases<A, B, ...> attribute.");
~~~~~~~~~~^~
myinheritance.cpp:30:28: note: in instantiation of function template specialization 'refl::descriptor::get_bases<refl::descriptor::type_descriptor >' requested here
constexpr auto bases = get_bases(type);
^
myinheritance.cpp:52:5: note: in instantiation of function template specialization 'print_bases' requested here
print_bases();
^
In file included from myinheritance.cpp:2:
./../refl.hpp:2233:68: error: constexpr variable 'bases' must be initialized by a constant expression
constexpr auto bases = get_attributeattr::base_types(t);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
4 errors generated.clang cannot be compiled, but g ++ can be compiled

Compilation error with simple example

Hi, I was trying to perform a simple example but I am receiving a lot of errors during compilation.
I'm using gcc/g++ 8.4.0 and compiling the program with the following command:
g++ -std=c++17 -Wall -g main.cpp -o test

#define REFL_METADATA_FILE "reflmd/main.cpp"
#include "libs/refl.hpp"
#include <iostream>

struct pdu_types_struct
{
    REFL() // the reflmd file has been generated
    int var1= 28;
};

struct pdu_types_struct pdu_types;

int main(int argc, char **argv)
{
     for_each(refl::reflect(pdu_types).members, [&](auto member) {
      std::cout << member.name << "=" << member(pdu_types) << ";";
   });
    return 0;
} 

#include REFL_METADATA_FILE

With the code above, I receive the following errors:

g++ -std=c++17 -Wall -g main.cpp -o test   
In file included from main.cpp:2:
libs/refl.hpp: In instantiation of β€˜class refl::descriptor::type_descriptor<pdu_types_struct>’:
main.cpp:15:38:   required from here
libs/refl.hpp:1625:27: error: static assertion failed: This type does not support reflection!
             static_assert(refl::trait::is_reflectable_v<T>, "This type does not support reflection!");
                           ^~~~
libs/refl.hpp:2620:55: error: specialization of β€˜refl_impl::metadata::type_info__<pdu_types_struct>’ after instantiation
     namespace refl_impl::metadata { template<> struct type_info__<TypeName> { \
                                                       ^~~~~~~~~~~~~~~~~~~~~
reflmd/main.cpp:3:1: note: in expansion of macro β€˜REFL_TYPE’
 REFL_TYPE(pdu_types_struct)
 ^~~~~~~~~
libs/refl.hpp:2620:55: error: redefinition of β€˜struct refl_impl::metadata::type_info__<pdu_types_struct>’
     namespace refl_impl::metadata { template<> struct type_info__<TypeName> { \
                                                       ^~~~~~~~~~~~~~~~~~~~~
reflmd/main.cpp:3:1: note: in expansion of macro β€˜REFL_TYPE’
 REFL_TYPE(pdu_types_struct)
 ^~~~~~~~~
In file included from main.cpp:2:
libs/refl.hpp:373:20: note: previous definition of β€˜struct refl_impl::metadata::type_info__<pdu_types_struct>’
             struct type_info__

Is there some pre step to use the library I am missing or some additional argument when calling g++?

Regards

Use case question involving func() declared members

Hello, I have a usecase for this library and I'm not sure if its implemented and I'm trying to implement it wrong or if its still in the works. I am trying to get a key/value structure with reference to a structure and have it dynamically generated. I have the following code:

refl_CPP

on line 44 i'd like to be able to get the reference to the function in a std::function<> type. I'm not sure if this a feature currently in the library, but it would be an incredibly helpful usecase on my end.

Q: Calculating signature and checksum using constexpr in C++17

Hi,

Recently I have implemented a simple serialization using this library, but I came across a problem that I wasn't able to solve. My application relies on C++17 with MSVC which limits my choices of what I'm able to do with constexpr magic.

I'd like to create a template struct that is able to calculate the hash of the members in a structure based on their name and type. I could create an SFINAE template to return with the name of the phase types, even some STL containers, but I wasn't able to accumulate a const_string in a way to have the signature in one piece in compile-time and to hash it later. I could do that in runtime, but the purpose of that is to have a constant value generated from that not runtime.

My questions are how exactly accumulation works, and how can it be utilized in such a way to generate a signature string from the reflected type? (I even can skip the string concatenation and directly jump to the CRC32 accumulation, but the problem is the same still.)

My Crc32 algorithm looks like this. How can I possibly extract the reflected value to feed a structure in a similar way?

	template <Checksum CRC, char... Chars> struct Crc32Impl
	{
	};

	template <Checksum CRC, char Head, char... Tail> struct Crc32Impl<CRC, Head, Tail...>
	{
		static constexpr Checksum value = Crc32Impl<crcTable[static_cast<unsigned char>(CRC) ^ static_cast<unsigned char>(Head)] ^ (CRC >> 8), Tail...>::value;
	};

	template <Checksum CRC> struct Crc32Impl<CRC>
	{
		static constexpr Checksum value = CRC ^ 0xFFFFFFFF;
	};

	template <char... Chars> using Crc32 = Crc32Impl<0xFFFFFFFF, Chars...>;

	constexpr Checksum Crc32Rec(const char * s, const Checksum crc = 0xFFFFFFFF) noexcept
	{
		return *s == 0 ? crc ^ 0xFFFFFFFF : Crc32Rec(s + 1, crcTable[static_cast<unsigned char>(crc) ^ static_cast<unsigned char>(*s)] ^ (crc >> 8));
	}

GetDateFormat getter vs. the Win32 API

I've got a class with the following:

class MyClass
{
public:
   void SetDateFormat(int x);
   int GetDateFormat() const;
...
  // many dozens more getters and setters so that REFL_AUTO is not an option, if it matters.
};

REFL_TYPE(MyClass)
   REFL_FUNC(SetDateFormat, property())
   REFL_FUNC(GetDateFormat, property())
... // a lot more
REFL_END

constexpr auto type = refl::reflect<MyClass>();
constexpr auto members = get_members(type);

for_each(members, [&](auto member)
{
   if constexpr (refl::descriptor::is_property(member)
      if constexpr (refl::descriptor::is_writable(member))
      {
         auto reader = refl::descriptor::get_reader(member); // fails in Windows VS 2022
      }
      else
         ...
});

The issue is that GetDateFormat is a macro defined by the Window API. It messes up get_reader. Oddly, it doesn't mess up the for_each loop. If I change the code so that it doesn't call get_reader it compiles, and I can successfully process the getter (though not correctly for my requirements).

I have tried #undef GetDateFormat, but that makes no difference. I tried (GetDateFormat), which normally is how you prevent macro expansion, but that doesn't work inside a macro. I would try to make a change to get_reader but I don't understand the code well enough. I could brute force my way out of this by changing the name, but that has downline consequences beyond my control.

If you have any suggestions, I would appreciate them.

Automatically built list of child types

Hi! First of all: thank you for this exquisite library! I'm currently using a simple children attribute on base classes to supply it with derived type list. It works but adds an extra step for type registration - I have to both specify the base in the child and the child in the base.

At first I thought that due to the static nature of refl-cpp it's not possible to add new child types to the base type descriptor when the children are registered.

But maybe I'm missing something and there is a way. Did you think about this?

Is it possible to get at nested member objects ?

Thinking of writing a template engine (moustache) that can interpolate struct values into templates. However, it would be necessary to get at the values of nested member objects by name. Is it possible to do this using refl-cpp ?
Basically to permit something like {{p.addr.city}}

    struct address {
        std::string city;
    };

    struct person {
        address addr;
    };

Issues compiling under Clang11

Hi Veselin,
I'm seeing issues compiling under Clang11.
I will try another compiler, but wondering if I did something wrong, or if you haven't tried Clang11 yet.

Thanks very much,
Andy

Here are some of them:

refl.hpp:149:48: error: constructor parameter 'data' shadows the field 'data' of 'const_string' [-Werror,-Wshadow-field-in-constructor]
constexpr const_string(const char(&data)[N + 1]) noexcept
^
agmlog_csv_generator/../../include/gpu/refl.hpp:128:18: note: previous declaration is here
char data[N + 1];
^
agmlog_csv_generator/../../include/gpu/refl.hpp:259:48: error: constructor parameter 'data' shadows the field 'data' of 'const_string' [-Werror,-Wshadow-field-in-constructor]
constexpr const_string(const char(&data)[sizeof...(Idx) + 1], std::index_sequence<Idx...>) noexcept
^
agmlog_csv_generator/../../include/gpu/refl.hpp:128:18: note: previous declaration is here
char data[N + 1];
^
agmlog_csv_generator/../../include/gpu/refl.hpp:1938:44: error: constructor parameter 'friendly_name' shadows the field 'friendly_name' of 'property' [-Werror,-Wshadow-field-in-constructor]
constexpr property(const char* friendly_name) noexcept

Reflect Inheritance hierarchy

Is it possible to iterate over the base classes in any way?
I'm thinking about something like this:

template <typename T>
void myBindMembers(T *instance)
{
	for_each(refl::reflect<T>().baseClasses, [&](auto baseClass) {
		// Call recursive to catch all
		myBindMembers((typename decltype(baseClass)::value_type*) instance);		
	})
	// Access Attributes of base Type
	// Bind all members defined in the instance and it's base classes.
	
}

struct MyBase{
	int BaseA;
	int BaseB;
};

REFL_TYPE(MyBase, attr("Attribute for BaseA and BaseB"))
REFL_FIELD(BaseA)
REFL_FIELD(BaseB)
REFL_END

struct Sub{
	int SubC;
};

REFL_TYPE(Sub, attr("Attribute for SubC"))
// Base classes are defined at the beginning and terminated (so the counter can be reused)
REFL_BASE(MyBase)
// Possible more Base classs definitions.
REFL_BASE_END
REFL_FIELD(SubC)
REFL_END

Or is this possible using attributes? I didn't find a solution for this, as "get_attribute" does not accept a template type like BaseClass.

If there is a ForEach for attributes, then it could be combined with this https://stackoverflow.com/a/21512908 to build something equivalent out of attributes. But I couldn't find a way to iterate over attributes either.

PS: You've build a great library.

Variadic expansion order is guaranteed for brace initializer expressions

Hi folks,

I just stumbled over the following block in your code:

refl-cpp/refl.hpp

Lines 1442 to 1446 in fbdb82c

// This whole jazzy workaround is needed since C++ does not specify
// the order in which function arguments are evaluated and this leads
// to incorrect order of evaluation (noticeable when using indexes).
// Otherwise we could simply do std::make_tuple(f(Ts{}, Idx)...).
template <typename F, typename T, typename... Ts, size_t I, size_t... Idx, typename... Carry>

I had similar issues and found the following soltion:

https://stackoverflow.com/questions/61229653/mapping-odbc-bindings-to-function-callback-via-function-argument-evaluation-orde

However, this is apparently broken in current MSVC:

https://developercommunity.visualstudio.com/content/problem/1015101/invoking-a-constructor-using-brace-constructor-syn.html?childToView=1095038#comment-1095038

Regards, Marti

Usability/Feature questions: WebAssembly, C++20 concept type-traits, shorten macro for field-only definitions?

@veselink1 first: Thanks for making refl-cpp a nice open-source header-only library! πŸ‘
Sorry for the long post, which covers more than one -- albeit overlapping -- aspects.

We are evaluating porting our existing serialiser implementation (YaS - Yet-another-Serialiser) to a more modern C++20 standard using refl-cpp. Having compared several other alternatives, I find your library very neat, efficient, and in the spirit of the upcoming C++(23?) static reflection functionality. Even better: your library works as-is and with minimal requirement already now. Kudos for that! πŸ‘ ⭐ ⭐ ⭐ πŸ‘

While exploring the refl-cpp syntax, I gathered some usability and feature-type questions rather than issues. I was wondering whether you (or someone else reading this) would be willing to comment and/or advise on these.

I made a small example implementing a default streaming operator operator<< overload for reflection-annotated classes below to illustrate the MVP use-case which is very similar to our (or for that matter most other) serialisation use-cases.

My questions:

  1. Does refl-cpp support being transpiled to WebAssembly (WASM)?
    I tried to compile the simple serialiser example (which works nicely), but I am getting errors when transpiling to WASM. This probably linked to missing headers in the compiler explorer environment but I was wondering whether somebody else has some successes with this before diving deeper into this myself. Any help/experience related to this would be much appreciated!
  2. Is there already another way to detect/distinguish user-defined from default std-annotated types (ie. those controlled via REFL_NO_STD_SUPPORT), for example, via type-traits, concepts, or boolean function? If not -- while I found some workarounds (see below) -- would it be conceivable/useful to incorporate some of the aspects into refl-cpp or should this remain better in the user-code? My worry is that the list of possible std:: might get eventually very long and the workaround below is not very maintainable and probably better/less effort being incorporated at the location where these std:: annotations are defined. Just as a thought.
  3. We would be annotating nearly exclusively member fields and not functions - would it be possible to shorten the annotation macro to something like REFL_CUSTOM(type, fieldName1, fieldName2, ..., fieldNameN)? I tried my luck but am not good enough with macros (which seem to be unavoidable and absolutely justified in this case though). Or is this something we should implement ourselves? I found a nice solution using boost -- although that wouldn't probably a suitable dependency to be incorporated into refl-cpp.
  4. If you like and find the example below also useful for other users, shall we make a PR for this?

Any help/experience related to this would be much appreciated!

The example code -- also runnable on compiler-explorer:

//#define REFL_NO_STD_SUPPORT // Q2-alt: enable this to skip parsing std templates (notably std::string)
#include <https://raw.githubusercontent.com/veselink1/refl-cpp/master/include/refl.hpp>
#include <iostream>

namespace unique {
    template <typename, template <typename...> typename>
    struct is_instance_impl : public std::false_type {};

    template <template <typename...> typename U, typename...Ts>
    struct is_instance_impl<U<Ts...>, U> : public std::true_type {};
    template <typename T, template <typename ...> typename U>

    using is_instance = unique::is_instance_impl<std::decay_t<T>, U>;
}

template < class T >
constexpr bool isStdTemplate() {    
    return std::is_same<T, std::string>{}
    || unique::is_instance<T, std::basic_string>::value
    || unique::is_instance<T, std::basic_string_view>::value
    || unique::is_instance<T, std::tuple>::value
    || unique::is_instance<T, std::unique_ptr>::value
    || unique::is_instance<T, std::shared_ptr>::value
    || unique::is_instance<T, std::pair>::value
    || unique::is_instance<T, std::complex>::value;
}

template<class T>
concept ReflectableClass = refl::is_reflectable<T>() && std::is_class<T>::value /*&& !isStdTemplate<T>()*/; // Q2-alt: add perhaps trait to identify std templates

template<class T>
constexpr bool isReflectableClass() {
    return refl::is_reflectable<T>() && std::is_class<T>() /*&& !isStdTemplate<T>()*/;
}

// automatically generate/enable the '<<' stream operator for REFL_... annotated classes
template <ReflectableClass T>
constexpr std::ostream& operator<<(std::ostream& os, const T& value) {
    os << refl::reflect(value).name << "(";
    if constexpr (std::is_class<std::remove_reference_t<decltype(value)>>::value) {
        for_each(refl::reflect(value).members, [&](const auto member, const auto index) constexpr {
            if (index > 0) { // how to make this constexpr??
                os << ", ";
            }
            os << get_display_name(member) << '=' << member(value);
        });
        os << ')';
    }
    return os;
}

// Q3 - custom macros to shorten simple declarations with only member fields - Q: incorporate to refl-cpp? user-code?
// there must be something smarter?!?
// perhaps something like: https://stackoverflow.com/questions/29224493/wrap-each-element-in-variadic-macro-with-an-expression#answer-29225568
#define REFL_CUSTOM(typeName, ...) REFL_AUTO(type(typeName), __VA_ARGS__)
#define REFL_CUSTOM1(typeName, f1) REFL_AUTO(type(typeName), field(f1))
#define REFL_CUSTOM2(typeName, f1, f2) REFL_AUTO(type(typeName), field(f1), field(f2))
#define REFL_CUSTOM3(typeName, f1, f2, f3) REFL_AUTO(type(typeName), field(f1), field(f2), field(f3))
#define REFL_CUSTOM4(typeName, f1, f2, f3, f4) REFL_AUTO(type(typeName), field(f1), field(f2), field(f3), field(f4))
// [..]

// ############## test classes (user code) ###################################

struct OtherStruct {    
    const char* name = "test";
    int a; // default init value (int -> '0')
    int b{-1};
    std::string otherString = "Hello";
};

// following line is important for serialisation until 'reflexpr' is available (target: ~C++23)
//REFL_AUTO(type(OtherStruct), field(name), field(a), field(b), field(otherString))
//REFL_CUSTOM(OtherStruct, field(name), field(a), field(b), field(otherString))
REFL_CUSTOM4(OtherStruct, name, a, b, otherString) // much shorter than the 'official version below


struct UnknownClass {
    int unknownValue;
};

struct DomainObject {    
    float x;
    float y;
    OtherStruct innerClass;
};

// alt declaration option (more verbose)
REFL_TYPE(DomainObject)    
    REFL_FIELD(x)
    REFL_FIELD(y)
    REFL_FIELD(innerClass)
REFL_END

#include <list> // just needed for test-case
int main() {
    const auto obj = DomainObject{41, 42};
    std::cout << "toStream: " << obj << "\n";
    std::cout << "toStream: " << DomainObject{43, 44} << "\n\n";

    std::cout << std::boolalpha;
    std::cout << "isReflectableClass(DomainObject) = " << isReflectableClass<DomainObject>() << '\n';  // true, OK
    std::cout << "isReflectableClass(OtherStruct) = " << isReflectableClass<OtherStruct>() << '\n';    // true, OK
    std::cout << "isReflectableClass(int) = " << isReflectableClass<int>() << '\n';                    // false, OK -- skip non-classes
    std::cout << "isReflectableClass(UnknownClass) = " << isReflectableClass<UnknownClass>() << '\n';  // false, OK -- skip non-REFL_AUTO classes
    std::cout << "isReflectableClass(std::string) = " << isReflectableClass<std::string>() << "\n\n";  // true, not OK --Q-B) should skip, why is std::string being reflected?

    std::cout << "isStdTemplate(std::string) = " << isStdTemplate<std::string>() << '\n';        // true, OK - not implemented
    std::cout << "isStdTemplate(std::tuple) = " << isStdTemplate<std::tuple<int,int>>() << '\n'; // true, OK - not implemented
    std::cout << "isStdTemplate(std::list) = " << isStdTemplate<std::list<int>>() << '\n';       // false, OK - not implemented
}

Feature: Better base type support in type_descriptor

Problem

The base types of a type can be specified with the base_types<Ts...> attribute (or via the bases<Ts...> template variable). To get a usable type_list one has to currently use a combination of get_attribute, decltype and the type_list member typedef of base_types. This is bad for usability.

Solution

Add better support for enumerating base types by exposing a typedef and a member type_list on type_descriptor, implemented on top of base_types. Expose these via type_descriptor and in the refl:: and refl::descriptor:: namespaces for similarity with member_list.

Possible interface

  1. Have base_types and indirect_base_types types, where the first variant is the directly declared bases, and the indirect variant is the full list of all direct and indirect bases.
  2. Have declared_base_types and base_types types, where the first variant is the directly declared bases, and the indirect variant is the full list of all direct and indirect bases. This matches better with the naming convention in #27 (Support inherited members) but might be less clear.

anoying unused parameters

Capture d’écran 2019-09-13 aΜ€ 08 59 42

You can use attribute [[maybe_unused]] or remove the variable name in signature of the function to silent the warnings please

Use of `get_reader` and `has_writer` produces absurdly long compile times

I use refl-hpp to import C++ classes into LuaBridge. A requirement of LuaBridge is that to import a writable property you must import its getter and setter at the same time. I have hacked around this with modifications to LuaBridge that allow me to import the setters separately, but these hacks are not safe in the long term and will not be merged back into the LuaBridge repository.

An alternative is to use get_reader and has_writer to import the properties correctly. These work, but they increase the compile-time cpu and memory requirements by a factor of 10x or more. What I've noticed in general with refl-cpp is that these requirements seem to increase exponentially with the number of members in the REFL_TYPE.

My code looks something like this:

template<class T>
void ProcessClass()
{
   constexpr auto type = refl::reflect<T>();
   constexpr auto members = get_members(type);

   for_each(members, [&](auto member)
   {
      if constexpr (refl::descriptor::is_property(member))
      {
         if constexpr (refl::descriptor::is_writable(member))
         {
            auto reader = refl::descriptor::get_reader(member);
            // etc.
         }
         else if constexpr (! refl::descriptor::has_writer(member))
         {
            // etc.
         }
      }
   });
}

I am wondering if you have a suggestion as to how to refactor this code to be more efficient at compile time. Is there some kind of hash table like std::map that runs at compile time? I have searched but couldn't find one. It would be nice if get_writer and get_reader could do a hash lookup on the display name rather than using find_one. I could pre-process the members in a separate loop if need be, but I haven't been able to figure out how.

constexpr if not a constant expression when using filter functions with const_string<N>

constexpr auto contains(type_list<Ts...> list, const const_string<N>& name);
constexpr auto find_one(type_list<Ts...> list, const const_string<N>& name);

The overloads taking a const_string<N> do not work reliably. These functions currently wrap the passed in string in a lambda, which is later called in a constexpr context in filter(...). This does not work, as the captured variables by the lambda do not form a constant expression. The workaround is to pass in a lambda doing the comparison explicitly:

find_one(member_list<T>{}, [](auto member) { return member.name == "mymethod"; });

Some further investigation is required, but these will most likely end up being removed in the next release.

base class function reflected ?

Hello

i have the following snippet:

#include "antara/gaming/core/safe.refl.hpp"
#include "antara/gaming/math/vector.hpp"

namespace antara::gaming::transform
{
    struct position_2d : public math::vec2f
    {
        template<typename ... Args>
        position_2d(Args&& ...args) noexcept: math::vec2f(std::forward<Args>(args)...)
        {

        }

        decltype(auto) x()
        {
            return math::vec2f::x();
        }

        decltype(auto) y()
        {
            return math::vec2f::y();
        }
    };
}

REFL_AUTO(type(antara::gaming::transform::position_2d), func(x), func(y))

I would like if possible to remove the x y function that i add to reflect correctly my base class

but when i try to invoke x() or y() without my trick it's not a valid pointer to member

It's possible to reflect base class functions ?

my full vector class which use mixins:

namespace antara::gaming::math
{
    template<class Unit, size_t Size, template<class> class...Mixins>
    class basic_vector : public Mixins<basic_vector<Unit, Size, Mixins...>> ...
    {

        template<class, size_t, template<class> class...>
        friend
        class basic_vector;

        using sequence_type = std::make_index_sequence<Size>;

        template<class Res, size_t...Is>
        constexpr auto implicit_cast_to(std::index_sequence<Is...>) const noexcept
        {
            return Res{std::get<Is>(data_)...};
        }

        template<class Res, size_t...Is>
        constexpr auto explicit_cast_to(std::index_sequence<Is...>) const noexcept
        {
            using NewUnit = typename Res::value_type;
            return Res{static_cast<NewUnit>(std::get<Is>(data_))...};
        }

        template<class F, size_t...Is>
        constexpr basic_vector make_vec(F &&f, std::index_sequence<Is...>) const noexcept
        {
            return {f(std::get<Is>(data_))...};
        }

        template<class F, size_t...Is>
        constexpr basic_vector make_vec(F &&f, basic_vector const &rhs, std::index_sequence<Is...>) const noexcept
        {
            return {f(std::get<Is>(data_), std::get<Is>(rhs.data_))...};
        }

        template<class F, size_t...Is>
        constexpr void update_vec(F &&f, std::index_sequence<Is...>) noexcept
        {
            (f(std::get<Is>(data_)), ...);
        }

        template<class F, size_t...Is>
        constexpr void update_vec(F &&f, basic_vector const &rhs, std::index_sequence<Is...>) noexcept
        {
            (f(std::get<Is>(data_), std::get<Is>(rhs.data_)), ...);
        }

        template<size_t...Is>
        constexpr Unit square_length(std::index_sequence<Is...>) const noexcept
        {
            return (... + (std::get<Is>(data_) * std::get<Is>(data_)));
        }

        template<class F, class Vec, size_t...Is>
        constexpr bool test_predicate(F &&f, Vec const &rhs, std::index_sequence<Is...>) const noexcept
        {
            return (f(std::get<Is>(data_), std::get<Is>(rhs.data_)) && ...);
        }

        std::array<Unit, Size> data_;
    public:
        using value_type = Unit;

        // Aggregate-like constructor
        template<class...Args, class = std::enable_if_t<
                std::conjunction_v<std::is_convertible<Args, Unit>...>
        >>
        constexpr basic_vector(Args...args) noexcept : data_{args...}
        {}

        constexpr basic_vector(Unit single_value) noexcept
        {
            std::fill(begin(), end(), single_value);
        }

        static constexpr auto scalar(Unit single_value) noexcept
        {
            return basic_vector(single_value);
        }

        constexpr Unit operator[](int i) const noexcept
        { return data_[i]; }

        constexpr Unit &operator[](int i) noexcept
        { return data_[i]; }

        template<size_t I>
        constexpr Unit get() const noexcept
        {
            static_assert(I >= 0 && I < Size, "Index outside of bounds");
            return std::get<I>(data_);
        }

        template<size_t I>
        constexpr Unit &get() noexcept
        {
            static_assert(I >= 0 && I < Size, "Index outside of bounds");
            return std::get<I>(data_);
        }

        constexpr Unit *data() noexcept
        { return data_.data(); }

        constexpr Unit const *data() const noexcept
        { return data_.data(); }

        constexpr int size() const noexcept
        { return Size; }

        constexpr auto begin() noexcept
        { return data_.begin(); }

        constexpr auto begin() const noexcept
        { return data_.begin(); }

        constexpr auto end() noexcept
        { return data_.end(); }

        constexpr auto end() const noexcept
        { return data_.end(); }

        // Implicit cast
        template<class NewUnit, template<class> class...NewMixins>
        constexpr operator basic_vector<NewUnit, Size, NewMixins...>() const noexcept
        {
            static_assert(std::is_convertible_v<Unit, NewUnit>, "Impossible cast from [value_type] to [NewUnit]");
            return implicit_cast_to<basic_vector<NewUnit, Size, NewMixins...>>(sequence_type{});
        }

        // Explicit cast
        template<class Vec>
        constexpr Vec to() const noexcept
        {
            using NewUnit = typename Vec::value_type;
            static_assert(std::is_convertible_v<Unit, NewUnit>,
                          "Impossible cast from [value_type] to [Vec::value_type]");
            return explicit_cast_to<Vec>(sequence_type{});
        }

        constexpr basic_vector operator+(Unit b) const noexcept
        {
            return make_vec([b](Unit a) { return a + b; }, sequence_type{});
        }

        constexpr basic_vector operator-(Unit b) const noexcept
        {
            return make_vec([b](Unit a) { return a - b; }, sequence_type{});
        }

        constexpr basic_vector operator*(Unit b) const noexcept
        {
            return make_vec([b](Unit a) { return a * b; }, sequence_type{});
        }

        constexpr basic_vector operator/(Unit b) const noexcept
        {
            return make_vec([b](Unit a) { return a / b; }, sequence_type{});
        }

        constexpr basic_vector operator+(basic_vector const &rhs) const noexcept
        {
            return make_vec([](Unit a, Unit b) { return a + b; }, rhs, sequence_type{});
        }

        constexpr basic_vector operator-(basic_vector const &rhs) const noexcept
        {
            return make_vec([](Unit a, Unit b) { return a - b; }, rhs, sequence_type{});
        }

        constexpr basic_vector operator*(basic_vector const &rhs) const noexcept
        {
            return make_vec([](Unit a, Unit b) { return a * b; }, rhs, sequence_type{});
        }

        constexpr basic_vector operator/(basic_vector const &rhs) const noexcept
        {
            return make_vec([](Unit a, Unit b) { return a / b; }, rhs, sequence_type{});
        }

        constexpr basic_vector &operator+=(Unit b) noexcept
        {
            update_vec([b](Unit &a) { a += b; }, sequence_type{});
            return *this;
        }

        constexpr basic_vector &operator-=(Unit b) noexcept
        {
            update_vec([b](Unit &a) { a -= b; }, sequence_type{});
            return *this;
        }

        constexpr basic_vector &operator*=(Unit b) noexcept
        {
            update_vec([b](Unit &a) { a *= b; }, sequence_type{});
            return *this;
        }

        constexpr basic_vector &operator/=(Unit b) noexcept
        {
            update_vec([b](Unit &a) { a /= b; }, sequence_type{});
            return *this;
        }

        constexpr basic_vector &operator+=(basic_vector const &rhs) noexcept
        {
            update_vec([](Unit &a, Unit b) { a += b; }, rhs, sequence_type{});
            return *this;
        }

        constexpr basic_vector &operator-=(basic_vector const &rhs) noexcept
        {
            update_vec([](Unit &a, Unit b) { a -= b; }, rhs, sequence_type{});
            return *this;
        }

        constexpr basic_vector &operator*=(basic_vector const &rhs) noexcept
        {
            update_vec([](Unit &a, Unit b) { a *= b; }, rhs, sequence_type{});
            return *this;
        }

        constexpr basic_vector &operator/=(basic_vector const &rhs) noexcept
        {
            update_vec([](Unit &a, Unit b) { a /= b; }, rhs, sequence_type{});
            return *this;
        }

        constexpr basic_vector operator-() const noexcept
        {
            return make_vec([](Unit x) { return -x; }, sequence_type{});
        }

        constexpr Unit square_length() const noexcept
        {
            return square_length(sequence_type{});
        }

        constexpr Unit length() const noexcept
        {
            return std::sqrt(square_length());
        }

        constexpr basic_vector normalized() const noexcept
        {
            return *this / length();
        }

        template<class NewUnit, template<class> class...NewMixins>
        constexpr bool operator==(basic_vector<NewUnit, Size, NewMixins...> const &rhs) const noexcept
        {
            return test_predicate([](Unit a, Unit b) { return a == b; }, rhs, sequence_type{});
        }

        template<class NewUnit, template<class> class...NewMixins>
        constexpr bool operator!=(basic_vector<NewUnit, Size, NewMixins...> const &rhs) const noexcept
        {
            return !(*this == rhs);
        }

        template<class NewUnit, template<class> class...NewMixins>
        constexpr bool operator<(basic_vector<NewUnit, Size, NewMixins...> const &rhs) const noexcept
        {
            return test_predicate([](Unit a, Unit b) { return a < b; }, rhs, sequence_type{});
        }

        template<class NewUnit, template<class> class...NewMixins>
        constexpr bool operator>=(basic_vector<NewUnit, Size, NewMixins...> const &rhs) const noexcept
        {
            return !(*this < rhs);
        }

        template<class NewUnit, template<class> class...NewMixins>
        constexpr bool operator>(basic_vector<NewUnit, Size, NewMixins...> const &rhs) const noexcept
        {
            return rhs < *this;
        }

        template<class NewUnit, template<class> class...NewMixins>
        constexpr bool operator<=(basic_vector<NewUnit, Size, NewMixins...> const &rhs) const noexcept
        {
            return !(rhs < *this);
        }
    };

    namespace vector_mixins
    {
        template<class Derived>
        class access_xy
        {
        public:
            constexpr auto x() const noexcept
            { return static_cast<Derived const *>(this)->template get<0>(); }

            constexpr auto &x() noexcept
            { return static_cast<Derived *>(this)->template get<0>(); }

            constexpr auto y() const noexcept
            { return static_cast<Derived const *>(this)->template get<1>(); }

            constexpr auto &y() noexcept
            { return static_cast<Derived *>(this)->template get<1>(); }
        };

        template<class Derived>
        class access_z
        {
        public:
            constexpr auto z() const noexcept
            { return static_cast<Derived const *>(this)->template get<2>(); }

            constexpr auto &z() noexcept
            { return static_cast<Derived *>(this)->template get<2>(); }
        };
    }

    template<class Unit>
    using vec2 = basic_vector<Unit, 2, vector_mixins::access_xy>;

    using vec2c   = vec2<char>;
    using vec2uc  = vec2<unsigned char>;
    using vec2s   = vec2<short>;
    using vec2us  = vec2<unsigned short>;
    using vec2i   = vec2<int>;
    using vec2u   = vec2<unsigned>;
    using vec2l   = vec2<long>;
    using vec2ul  = vec2<unsigned long>;
    using vec2ll  = vec2<long long>;
    using vec2ull = vec2<unsigned long long>;
    using vec2f   = vec2<float>;
    using vec2d   = vec2<double>;
    using vec2ld  = vec2<long double>;

    template<class Unit>
    using vec3 = basic_vector<Unit, 3, vector_mixins::access_xy, vector_mixins::access_z>;

    using vec3c   = vec3<char>;
    using vec3uc  = vec3<unsigned char>;
    using vec3s   = vec3<short>;
    using vec3us  = vec3<unsigned short>;
    using vec3i   = vec3<int>;
    using vec3u   = vec3<unsigned>;
    using vec3l   = vec3<long>;
    using vec3ul  = vec3<unsigned long>;
    using vec3ll  = vec3<long long>;
    using vec3ull = vec3<unsigned long long>;
    using vec3f   = vec3<float>;
    using vec3d   = vec3<double>;
    using vec3ld = vec3<long double>;
}

namespace std {

    template<class Unit, size_t Size, template<class> class...Mixins>
    struct tuple_size<antara::gaming::math::basic_vector<Unit, Size, Mixins...>> : integral_constant<size_t, Size> {};

    template <size_t I, class Unit, size_t Size, template<class> class...Mixins>
    struct tuple_element<I, antara::gaming::math::basic_vector<Unit, Size, Mixins...>> { using type = Unit; };
}

refl::util::detail::filter(..) inverts order of member list

There might be a regression in the last refl-cpp release:
refl::util::detail::filter(..) seems to invert the member order which has a notable impact on the find_first() method.

#include <iostream>
#include <https://raw.githubusercontent.com/veselink1/refl-cpp/master/include/refl.hpp>

struct Point {
    float x;
    float y;
    float z;
};
REFL_TYPE(Point)
    REFL_FIELD(x)
    REFL_FIELD(y)
    REFL_FIELD(z)
REFL_END

constexpr auto members = refl::reflect<Point>().members;
constexpr auto condition = [](auto member) { return true; };
static_assert(find_first(members, condition).name == "x");  // <- fails but should be correct
// static_assert(find_first(members, condition).name == "z"); // works

See compiler-explorer for further details and a live demo of this feature.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.