Обобщение указателя на член - это функция, которая может отображать T
на X&
во время компиляции.
В c ++ 17 подключить не сложновсе благодаря auto
.В c ++ 11 становится все сложнее.Но основная идея состоит в том, что вы на самом деле не передаете указатели членов, вы передаете типы, и эти типы знают, как взять ваш класс и получить из него ссылку.
template<class T, class D, class...Fs>
struct MyData {
std::array<D*, sizeof...(Fs)> var = {};
explicit MyData()=default;
void set(T const& var_) {
var = {{ Fs{}(std::addressof(var_))... }};
}
T get() {
T var_;
std::size_t index = 0;
using discard=int[];
(void)discard{ 0, (void(
*Fs{}(std::addressof(var_)) = *var[index++]
),0)... };
return var_;
}
};
Осталось написатьутилита, облегчающая написание Fs...
для регистра указателя члена
template<class X, X M>
struct get_ptr_to_member_t;
template<class T, class D, D T::* M>
struct get_ptr_to_member_t< D T::*, M > {
D const* operator()( T const* t )const{
return std::addressof( t->*M );
}
};
#define TYPE_N_VAL(...) \
decltype(__VA_ARGS__), __VA_ARGS__
#define MEM_PTR(...) get_ptr_to_member_t< TYPE_N_VAL(__VA_ARGS__) >
теперь базовый регистр
MyData< Outer, double, MEM_PTR(&Outer::x), MEM_PTR(&Outer::y) >
Теперь можно обрабатывать более сложный регистр.
Один из подходов - научить get_ptr_to_member
сочинять.Это раздражающая работа, но ничего фундаментального.Компоновка такова, что decltype(ptr_to_member_t * ptr_to_member_t)
возвращает тип, который экземпляры вправо, применяет его, затем берет этот указатель и запускает на нем левую часть.
template<class First, class Second>
struct composed;
template<class D>
struct composes {};
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
template<class First, class Second>
struct composed:composes<composed<First, Second>> {
template<class In>
auto operator()(In&& in) const
RETURNS( Second{}( First{}( std::forward<In>(in) ) ) )
};
template<class First, class Second>
composed<First, Second> operator*( composes<Second> const&, composes<First> const& ) {
return {};
}
, затем мы обновляем:
template<class X, X M>
struct get_ptr_to_member_t;
template<class T, class D, D T::* M>
struct get_ptr_to_member_t< D T::*, M >:
composes<get_ptr_to_member_t< D T::*, M >>
{
D const* operator()( T const* t )const{
return std::addressof( t->*M );
}
};
и теперь *
составляет их.
MyData<TestStruct, double, MEM_PTR(&Outer::x),
MEM_PTR(&Outer::y),
MEM_PTR(&Outer::z),
decltype(MEM_PTR(&Inner::a){} * MEM_PTR(&Outer::in){})
> state();
ответ, вероятно, содержит много опечаток, но дизайн - это звук.
В c ++ 17 большая частьмусор испаряется, как макросы.