Giter VIP home page Giter VIP logo

visit_struct's People

Contributors

cbeck88 avatar ilue avatar kmcallister avatar traversaro avatar xenontrioxide avatar

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

visit_struct's Issues

"Intrusive" Syntax and member initialization

Hi, is it possible to to member initialization while using the "Intrusive" Syntax?

Something like the following:

struct my_type {
  BEGIN_VISITABLES(my_type);
  VISITABLE(int, a, 0);
  VISITABLE(float, b, 0.0);
  VISITABLE(std::string, c);
  END_VISITABLES;
};

conan package

It would be great if visit_struct been avalible in conan.io

Not compiling using Intel 16.0 (with Visual Studio 2013)

Hi,

very nice small thing! I tested it using Intel Compiler 16.0 (under Visual Studio 2013) but it does not work, unfortunately. Is there a chance that it could be fixed? Error message is " error #54: too few arguments in invocation of macro "VISIT_STRUCT_PP_MAP1". Thank you! With boost/Fusion it is working, but I strongly prefer your approach because of the much much smaller source-code-footprint (and also usage is more elegant).

Separate parser program for 'intrusive'

I've begun writing a short C++ program to take a normal header file like so:

	struct Monkey {
		int a;
		float b;
		char c[5];
	};

and turn it into:

	typedef char char_5[5];

	struct Monkey {
		BEGIN_VISITABLES(Monkey);
		VISITABLE(int, a);
		VISITABLE(float, b);
		VISITABLE(char_5, c);
		END_VISITABLES;
	};

I can show you what I have so far.

runtime versions of indexed access functions

It may be sometimes useful to have also runtime reflection. So I came up with some wrappers in GUI object properties editor code, like these:

#include "visit_struct/visit_struct.hpp"
#include <iostream>
#include <variant>
#include <string>

struct S {
    int n;
    float f;
    char c;
};
VISITABLE_STRUCT(S, n, f, c);

using var_type=std::variant<int,float,char>;

template<std::size_t I = 0, typename FuncT,typename T>
inline typename std::enable_if<I == visit_struct::field_count<T>(), void>::type
for_index(int, T&, FuncT)
{ }

template<std::size_t I = 0, typename FuncT,typename T>
inline typename std::enable_if<I < visit_struct::field_count<T>(), void>::type
for_index(int index, T& t, FuncT f)
{
    if (index == 0) f(visit_struct::get<I>(t));
    for_index<I + 1, FuncT>(index-1, t, f);
}

template<typename T>
var_type get_variant(const T& t,int i)
{
    var_type var;
    for_index(i,t,[&var](auto&& v) {
        var=v;
    });
    return var;
}

template<typename T>
void set_field(T& t, const var_type& var, int i)
{
    for_index(i,t,[&i,&var](auto&& prop) {
        std::visit([&prop](auto&& v) {
            prop=v;
        },var);
    });
}

int main()
{
    S s{42,3.14,'Z'};
    auto printer=[](auto&& v) {
        std::cout<<v<<'\n';
    };
    var_type var;
    var=get_variant(s,2);
    std::visit(printer,var);

    var=2.718f;
    set_field(s,var,1);
    var=get_variant(s,1);
    std::visit(printer,var);
    return 0;
}

It is far from complete and is probably not the best way to implement it, but shows the idea. Would it be useful to have similar wrappers as a part of visit_struct?

compile error with boost fusion

  • compiler: g++ 11 std=20
  • boost 1.77
  • visit_struct: 8c91d22

source code trigger the error

#include <visit_struct/visit_struct_boost_fusion.hpp>
BOOST_FUSION_DEFINE_STRUCT((), FusionParams,
                           (int, param1)(double, param2))

template <class Params>
constexpr void PopulateVsFoo(const Params& params) {
  visit_struct::for_each(params, []<typename T>(const char*, const T&) {});
}

void test() {
  FusionParams p;
  PopulateVsFoo(p);
}

compile error:

In file included from /param_test.cpp:1:
/visit_struct/include/visit_struct/visit_struct_boost_fusion.hpp: In instantiation of 'static void visit_struct::traits::visitable<S, typename std::enable_if<std::is_same<typename boost::mpl::sequence_tag<Sequence>::type, boost::fusion::fusion_sequence_tag>::value>::type>::apply(V&&, T&&) [with V = PopulateVsFoo<{anonymous}::FusionParams>(const {anonymous}::FusionParams&)::<lambda(const char*, const T&)>; T = const {anonymous}::FusionParams&; S = {anonymous}::FusionParams]':
/visit_struct/include/visit_struct/visit_struct.hpp:144:47:   required from 'constexpr typename std::enable_if<visit_struct::traits::is_visitable<typename visit_struct::traits::clean<S>::type>::value>::type visit_struct::for_each(S&&, V&&) [with V = PopulateVsFoo<{anonymous}::FusionParams>(const {anonymous}::FusionParams&)::<lambda(const char*, const T&)>; S = const {anonymous}::FusionParams&; typename std::enable_if<visit_struct::traits::is_visitable<typename visit_struct::traits::clean<S>::type>::value>::type = void; typename visit_struct::traits::clean<S>::type = {anonymous}::FusionParams]'
/param_test.cpp:6:25:   required from 'constexpr void PopulateVsFoo(const Params&) [with Params = {anonymous}::FusionParams]'
/param_test.cpp:11:16:   required from here
/visit_struct/include/visit_struct/visit_struct_boost_fusion.hpp:133:21: error: use of deleted function 'visit_struct::traits::visitable<{anonymous}::FusionParams, void>::fusion_visitor<PopulateVsFoo<{anonymous}::FusionParams>(const {anonymous}::FusionParams&)::<lambda(const char*, const T&)>&&, const {anonymous}::FusionParams&>::fusion_visitor(const visit_struct::traits::visitable<{anonymous}::FusionParams, void>::fusion_visitor<PopulateVsFoo<{anonymous}::FusionParams>(const {anonymous}::FusionParams&)::<lambda(const char*, const T&)>&&, const {anonymous}::FusionParams&>&)'
  133 |     fusion::for_each(Indices(), fv);
      |     ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
/visit_struct/include/visit_struct/visit_struct_boost_fusion.hpp:66:10: note: 'visit_struct::traits::visitable<{anonymous}::FusionParams, void>::fusion_visitor<PopulateVsFoo<{anonymous}::FusionParams>(const {anonymous}::FusionParams&)::<lambda(const char*, const T&)>&&, const {anonymous}::FusionParams&>::fusion_visitor(const visit_struct::traits::visitable<{anonymous}::FusionParams, void>::fusion_visitor<PopulateVsFoo<{anonymous}::FusionParams>(const {anonymous}::FusionParams&)::<lambda(const char*, const T&)>&&, const {anonymous}::FusionParams&>&)' is implicitly deleted because the default definition would be ill-formed:
   66 |   struct fusion_visitor {
      |          ^~~~~~~~~~~~~~
/visit_struct/include/visit_struct/visit_struct_boost_fusion.hpp:66:10: error: copying non-static data member 'PopulateVsFoo<{anonymous}::FusionParams>(const {anonymous}::FusionParams&)::<lambda(const char*, const T&)>&& visit_struct::traits::visitable<{anonymous}::FusionParams, void>::fusion_visitor<PopulateVsFoo<{anonymous}::FusionParams>(const {anonymous}::FusionParams&)::<lambda(const char*, const T&)>&&, const {anonymous}::FusionParams&>::visitor' of rvalue reference type
In file included from /boost/fusion/include/for_each.hpp:11,
                 from /visit_struct/include/visit_struct/visit_struct_boost_fusion.hpp:12,
                 from /param_test.cpp:1:
/boost/fusion/algorithm/iteration/for_each.hpp:41:37: note:   initializing argument 2 of 'constexpr typename boost::enable_if<boost::fusion::traits::is_sequence<Sequence> >::type boost::fusion::for_each(const Sequence&, F) [with Sequence = boost::mpl::range_c<unsigned int, 0, 2>; F = visit_struct::traits::visitable<{anonymous}::FusionParams, void>::fusion_visitor<PopulateVsFoo<{anonymous}::FusionParams>(const {anonymous}::FusionParams&)::<lambda(const char*, const T&)>&&, const {anonymous}::FusionParams&>; typename boost::enable_if<boost::fusion::traits::is_sequence<Sequence> >::type = void]'
   41 |     for_each(Sequence const& seq, F f)
      |                                   ~~^

Exposing private members

My team and I are thinking of using this library to expose a class into our UI automatically. However, the class we want to expose has some private members that should also be exposed. I haven't seen anyone mention this so I'm wondering if there is a way to do this.

Get member variable pointer at compile-time

visit_pointers passes the member variable pointers to the given callable. At this point, the constexpr-ness of the pointer is lost. visit_accessors passes accessor objects to the given callable. accessor has the pointer as a template parameter. I propose adding this to accessor:

static VISIT_STRUCT_CONSTEXPR auto value = ptr;

This would make it possible to access the pointer as a compile-time constant.

Visiting template classes

What is the right way to visit template classes/structs? I am using the intrusive macros, but seem to be able to only mark 2 fields as visitable. Any more, and I get functions that differ only in their return type cannot be overloaded errors.

Feature request: optional visitable metadata

I'm using visit_struct to declare structs with parameters and automatically link specific option values to GUI widgets. It works great for simple cases.

However, more often than not I would like to define additional metadata where I specify the options in the struct. For example for numeric options, I would like to specify a range with minimum and maximum acceptable value, such that a slider with the correct limits can be created in the GUI.

I'm currently working around this by using some custom types for the struct member variables, e.g.

template <class T>
struct ranged {
  using ValueType = T;
  T val {0};
  const T min {0};
  const T max {100};
};

struct Foo {

    BEGIN_VISITABLES(Foo);

    VISITABLE_INIT(bool, foo, true);
    VISITABLE_DIRECT_INIT(ranged<double>, bar, {0.5, 0, 1});
    END_VISITABLES;

};

However this is a bit awkward, as a I have to access the actual value always via the val member.

Foo foo;
foo.bar.val = 0.1;

Would it be possible to extend visit_struct to allow declaring additional (typed) meta-data for every member in such a way, that it is transparent (i.e. foo.bar refers to the actual value, not some enclosing struct containing also the metadata), and it is (optionally) accessible during visitation.

I guess for my use-cases I so far only need constant meta-data.

I'm mostly interested in the intrusive syntax, since I want to define "all in one place", but one might also consider adding metadata to existing structs with a non-intrusive syntax.

Recursive Serialization, decltype and is_visitable behaving strangely

I'm trying to write a function which, given some passed-in visitable struct, will recursively serialize all of its members that are marked visitable (I use the instrusive method).

template<typename T>
char* visitSerialize(const T& type) {
    visit_struct::for_each(type, [](const char* name, const auto & value) {
        if (visit_struct::traits::is_visitable<decltype(value)>::value) {
            println("visitable! %s", name);
        }
    });
    return ""; // @TODO
}

my plan was to recursively call visitSerialize on members of the currently-being-visited struct, if the member I am currently inspecting is visitable. However, value in the arguments to my callback is never considered visitable by the expression visit_struct::traits::is_visitable<decltype(value)>::value, despite them being marked as such in my header file(s). Here's a simple example:

I start by calling visitSerialize on an instance of this:

typedef struct Level {
    BEGIN_VISITABLES(Level);
    VISITABLE(char*, name);

    VISITABLE(Terrain*, terrain);
    VISITABLE(WaterRect*, waterRects);
    VISITABLE(Entity*, entities);
    VISITABLE(Skybox*, skybox);
    VISITABLE(PointLight*, pointLights);
    VISITABLE(DirLight*, dirLights);
    VISITABLE(SpotLight*, spotLights);

    VISITABLE(u32, numWaterRects);
    VISITABLE(u32, numEntities);
    VISITABLE(u32, numPointLights);
    VISITABLE(u32, numDirLights);
    VISITABLE(u32, numSpotLights);

    u32 terrainShaderId;
    u32 entityShaderId;
    END_VISITABLES;
} Level;

None of the struct types there are considered visitable. Here's water.h:

typedef struct WaterRect {
    BEGIN_VISITABLES(WaterRect);
    VISITABLE(glm::vec3, origin);
    VISITABLE(float, xwidth);
    VISITABLE(float, zwidth);

    VISITABLE(float, moveSpeed);
    VISITABLE(float, moveFactor);
    VISITABLE(float, waveStrength);

    u32 refractionFramebuffer;
    u32 refractionTextureId;
    u32 refractionDepthTextureId;

    u32 reflectionFramebuffer;
    u32 reflectionTextureId;

    VISITABLE(glm::vec4, color);
    END_VISITABLES;
} WaterRect;

Am I missing something? Is there a better way? Does decltype not work the way I thought?

I'm not a C++ template guy so a lot of this stuff is black magic to me. Thanks.

Implement binary visitation

This was mentioned on reddit as a potentially very useful feature, as you could use it to implement equality and comparison operators.

Does it support inheritance?

Say, I have such code:

struct A {
  BEGIN_VISITABLES(A);
  VISITABLE(int, x);
  END_VISITABLES;
};

struct B:A {
  BEGIN_VISITABLES(B);
  VISITABLE(int, y)
  END_VISITABLES;
}

Does it work?

Clang: Compilation error with visitable struct include template class

I ran into problems getting the following to work in Clang 12.0.0, using the latest master of visit_struct:

template <typename T>
struct TemplatedStruct
{
	struct Visitable
	{
		BEGIN_VISITABLES(Visitable);
		VISITABLE(int, a);
		VISITABLE(int, b);
		VISITABLE(int, c);
		END_VISITABLES;
	};
};

int main(int argc, char** argv)
{
	TemplatedStruct<int> test;
	return 0;
}

For this minimal example, Clang outputs the following:

main.cpp:12:3: error: functions that differ only in their return type cannot be overloaded
VISITABLE(int, c);
^~~~~~~~~~~~~~~~~
visit_struct/include/visit_struct/visit_struct_intrusive.hpp:382:3: note: expanded from macro 'VISITABLE'
Visit_Struct_Get_Visitables__(::visit_struct::detail::Rank<VISIT_STRUCT_GET_REGISTERED_MEMBERS::size + 1>);
^
main.cpp:11:3: note: previous declaration is here
VISITABLE(int, b);
^~~~~~~~~~~~~~~~~
visit_struct/include/visit_struct/visit_struct_intrusive.hpp:382:3: note: expanded from macro 'VISITABLE'
Visit_Struct_Get_Visitables__(::visit_struct::detail::Rank<VISIT_STRUCT_GET_REGISTERED_MEMBERS::size + 1>);
^
1 error generated.

Both GCC and MSVC compile this example just fine, only Clang has problems with it. The problem happens only with visitable structs inside template classes. Without the template, it works just fine. Curiously, it also works fine with exactly 2 visitables in the struct - it starts failing for 3.

Non const visitor function arguments

Hello,

This is an awesome library. It has saved me a lot of time and effort.

Currently I'm attempting to use visit_struct to implement generic deep cloning. My idea was to use the binary for_each method to recursively clone members from one struct to the other.

struct copy_visitor;

template <typename T,
    std::enable_if_t<visit_struct::traits::is_visitable<std::decay_t<T>>::value, int> = 0>
T clone_struct(const T& src)
{
    T dst;
    copy_visitor vis;
    visit_struct::for_each(dst, src, vis);
    return dst;
}

template <typename T,
    std::enable_if_t<!visit_struct::traits::is_visitable<std::decay_t<T>>::value, int> = 0>
T clone_struct(const T& src)
{
    T dst;
    dst = src;
    return dst;
}

struct copy_visitor {
    template <typename T>
    void operator()(const char* name, T& dst, T& src) {
        dst = clone_struct(src);
    }
};

My issue is that all of the visitor functions want to operate on const arguments. Is there a way to implement something along these lines with the existing interfaces provided? A way to set a property by name or index at runtime?

if constexpr type deduction in visitor?

I'm basically trying to determine type using if constexpr

#include <cxxabi.h>
#include <string>

const std::string demangle(const char* name) {
    int status = -4;
    char* res = abi::__cxa_demangle(name, NULL, NULL, &status);
    const char* const demangled_name = (status==0)?res:name;
    std::string ret_val(demangled_name);
    free(res);
    return ret_val;
}

#include <iostream>
#include <type_traits>

#include "visit_struct.hpp"

struct something
{
    char a[12];
    char lot[2];
    char of[35];
    char chars[20];
    int x;
};

VISITABLE_STRUCT(something, a, lot, of, chars, x);

something s1{"a", "l", "o", "c", 123};

void attempt1()
{
    visit_struct::for_each(s1, [&](const char* name, const auto& value) {
      std::cout << name << " = " << demangle(typeid(value).name()) << "\n";

      using value_type = decltype(value);
      
      if constexpr (std::is_same_v<value_type, int>)
        std::cout << name << " is int\n";
      else if constexpr (std::is_array_v<value_type>) {
        std::cout << name << " is array\n";
        
        using array_type = typename std::remove_all_extents<value_type>::type;
        if constexpr (std::is_same_v<char, array_type>) {
          std::cout << name << " is char array\n";
          return;
        }
      }
      else
        std::cout << name << " is not char array or int\n";
    });
}

int main()
{
  attempt1();
}

Output:

a = char [12]
a is not char array or int
lot = char [2]
lot is not char array or int
of = char [35]
of is not char array or int
chars = char [20]
chars is not char array or int
x = int
x is not char array or int

Doing

using value_type = visit_struct::type_at<0, something>;

seems to work for char arrays, but it doesn't solve my problem

Allow non-intrusive annotation of template types

A gap right now is that there is no good way to annotate template types using the VISITABLE_STRUCT macro. This may be necessary or desirable if you are using third party code and you don't want to modify the headers, but you want to be able to use their types in your serialization framework.

New release?

First of all, thaks a lot @garbageslam for the great library.

I was wondering if you were interesting in releasing a new version of the library, bumping the version in https://github.com/garbageslam/visit_struct/blob/8c91d2283c7050593df5b692a13cb0ea99ba81d5/include/visit_struct/visit_struct.hpp#L18 and creating a new tag? The current master contains some new features w.r.t. to the v1.0.0 release, and it would be great to have a release explicitly containing this new features.

Thanks a lot in advance.

QA

If the structure is nested in the structure, how to achieve it

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.