Variadic sequence of pointer to recursive member of struct/class as template parameter

  • A+
Category:Languages

I'm struggling with some template programming and I hope you can give me some help. I coded a C++11 interface that, given some structs like:

struct Inner{   double a; }; struct Outer{   double x, y, z, r;   Inner in; }; 

Implements a getter/setter to the real data that is customized to the specified struct members:

MyData<TestStruct, double, &Outer::x,                                &Outer::y,                                 &Outer::z,                                &Outer::in::a //This one is not working               > state();  Outer foo = state.get(); //...   state.set(foo); 

I managed to implement this for simple structs in the following way:

template <typename T, typename U, U T::* ... Ms> class MyData{    std::vector<U *> var;   public:     explicit MyData();     void set(T const& var_);     T get() const; };  template <typename T, typename U, U T::* ... Ms> MyData<T, U, Ms ... >::Struct():var(sizeof...(Ms)) { }  template <typename T, typename U, U T::* ... Ms> void MyData<T, U, Ms ...>::set(T const& var_){   unsigned i = 0;   for ( auto&& d : {Ms ...} ){     *var[i++] = var_.*d;   } }  template <typename T, typename U, U T::* ... Ms> T MyData<T, U, Ms ...>::get() const{   T var_;   unsigned i = 0;   for ( auto&& d : {Ms ...} ){     var_.*d = *var[i++];   }   return var_; } 

But it fails when I pass a member of a nested struct. Ideally, I'd like to implement a generic pointer to member type that allows me to be compatible with several levels of scope resolutions. I found this approach, but I'm not sure if this should be applied to my problem or if there exists some implementation ready to use. Thanks in advance!

Related posts:

Implicit template parameters

Pointer to inner struct

 


You might wrap member pointer into struct to allow easier chaining:

template <typename...> struct Accessor;  template <typename T, typename C, T (C::*m)> struct Accessor<std::integral_constant<T (C::*), m>> {     const T& get(const C& c) { return c.*m; }     T& get(C& c) { return c.*m; } };  template <typename T, typename C, T (C::*m), typename ...Ts> struct Accessor<std::integral_constant<T (C::*), m>, Ts...> {     auto get(const C& c) -> decltype(Accessor<Ts...>().get(c.*m))     { return Accessor<Ts...>().get(c.*m); }      auto get(C& c) -> decltype(Accessor<Ts...>().get(c.*m))     { return Accessor<Ts...>().get(c.*m); } };  template <typename T, typename U, typename ...Ts> class MyData {     std::vector<U> vars{sizeof...(Ts)};      template <std::size_t ... Is>     T get(std::index_sequence<Is...>) const     {         T res;         ((Ts{}.get(res) = vars[Is]), ...); // Fold expression C++17         return res;     }     template <std::size_t ... Is>     void set(std::index_sequence<Is...>, T const& t)     {         ((vars[Is] = Ts{}.get(t)), ...); // Fold expression C++17     }  public:     MyData() = default;      T get() const { return get(std::index_sequence_for<Ts...>()); }     void set(const T& t) { return set(std::index_sequence_for<Ts...>(), t); }  }; 

With usage similar to

template <auto ...ms> // C++17 too using Member = Accessor<std::integral_constant<decltype(ms), ms>...>;  MyData<Outer, double, Member<&Outer::x>,                            Member<&Outer::y>,                            Member<&Outer::z>,                            Member<&Outer::in, &Inner::a>        > state; 

std::index_sequence is C++14 but can be implemented in C++11.
Folding expression from C++17 can be simulated too in C++11.
typename <auto> (C++17) should be replaced by typename <typename T, T value>.

Demo

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: