How to implement a template that gets a class and a pointer to a member of this class?
I want to template a sort of Accessor
of the form
template<??? T, ??? P>
class Accessor
{
// ...
T& setMember(const Vector3d& point)
{
T& obj = getObject<T>();
obj.*P = point;
return obj;
}
};
Here, there is a class T
with a member P
, both template variables. I know that P
is always of type Vector3d
. But I have to stay within C++17. Of course, if you have a C++20 technique... I want to know!
Also, Accessor
does not have any reference to a T
object. But the function getObject
magically handles it here. Therefore do not need to care here.
I'd like to use it like this:
class Accessed
{
Vector3d one_point;
Vector3d another_point;
class OneAccessor : public Accessor<&one_point> {};
class AnotherAccessor : public Accessor<&another_point> {};
}
Notice the format : public Accessor<&one_point>
.
Maybe public Accessor<&Accessed::one_point>
.
I would prefer
public Accessor<one_point> // or
public Accessor<Accessed::one_point>
without the &
. I'd like Accessed::
to be inferred.
If you have an answer to my problem that you want to deliver, I would very much like to see it.
template <typename T>
struct class_type;
template<typename T>
struct class_type<Vector3d T::*> {
using type = T;
};
template<auto P>
struct Accessor
{
using T = typename class_type<decltype(P)>::type;
T& setMember(const Vector3d& point)
{
T& obj = getObject<T>();
obj.*P = point;
return obj;
}
};
class Accessed
{
Vector3d one_point;
Vector3d another_point;
class OneAccessor : public Accessor<&Accessed::one_point> {};
class AnotherAccessor : public Accessor<&Accessed::another_point> {};
};
Another version using variables:
template<typename T>
struct Accessor
{
Vector3d T::* p;
constexpr Accessor(Vector3d T::* p) :p{p} {}
T& setMember(const Vector3d& point)
{
T& obj = getObject<T>();
obj.*p = point;
return obj;
}
};
struct Accessed
{
Vector3d one_point;
Vector3d another_point;
static constexpr Accessor OneAccessor{&Accessed::one_point};
static constexpr Accessor AnotherAccessor{&Accessed::another_point};
};