c++ 指向类成员的指针作为模板参数

busg9geu  于 2023-03-20  发布在  其他
关注(0)|答案(3)|浏览(187)

如何实现一个获取类和指向该类成员的指针的模板?
我想创建一个类似Accessor的表单模板

template<??? T, ??? P>
class Accessor
{
    // ...

    T& setMember(const Vector3d& point)
    {
        T& obj = getObject<T>();
        obj.*P = point;
        return obj;
    }
};

这里有一个类T,它有一个成员P,两个都是模板变量。我知道P总是Vector3d类型。但是我必须停留在C17。当然,如果你有C20技术...我想知道!
同样,Accessor没有任何对T对象的引用,但是函数getObject在这里神奇地处理了它,因此这里不需要关心。
我想这样使用它:

class Accessed
{
    Vector3d one_point;
    Vector3d another_point;

    class OneAccessor : public Accessor<&one_point> {};
    class AnotherAccessor : public Accessor<&another_point> {};
}

注意格式:public Accessor<&one_point> .
也许是public Accessor<&Accessed::one_point>
我宁愿

public Accessor<one_point> // or 
public Accessor<Accessed::one_point>

而不使用&。我希望推断出Accessed::
如果你对我的问题有答案,我很想看看。

yr9zkbsy

yr9zkbsy1#

类成员指针的类成员类型可以通过trait找到,但是,语法Accessor<decltype(&Accessed::one_point)> elimination可能需要一个推导指南,我把它留给你。
假设Accessor将具有Accessed成员的内部状态,则可以按如下所示舍入解决方案:

#include <iostream>
#include <string>
#include <type_traits>

using Vector3d = std::string; // just for test

template <typename T> struct member {};
// traits for member type
template<typename Class, typename Type>
struct member<Type Class::*> {
    using mem_type = Type;
    using class_type = Class;
};
// alias types for convenience
template<typename T> using class_type_t = typename member<T>::class_type;
template<typename T> using mem_type_t = typename member<T>::mem_type;

template<typename T> class Accessor
{
    T mMember;
public:
    explicit Accessor(T mem)
        : mMember{mem}
    {}
    auto setMember(const Vector3d& point);  
};

class Accessed
{
    Vector3d one_point;
    Vector3d another_point;
public:

    struct OneAccessor : public Accessor<decltype(&Accessed::one_point)> {
        OneAccessor()
            : Accessor<decltype(&Accessed::one_point)>{ &Accessed::one_point }
        {}
        auto test(const Vector3d& point);
    };
    auto getOne() const { return one_point;  }
};

template<typename T>
auto Accessor<T>::setMember(const Vector3d& point)
{
    if constexpr (std::is_same_v<class_type_t<T>, Accessed>)
    {
        static class_type_t<T> obj{};
        obj.*mMember = point;
        return obj;
    }
}

auto Accessed::OneAccessor::test(const Vector3d& point)
{
    return this->setMember(point);
}

int main()
{
    Accessed::OneAccessor ob;
    auto var = ob.test("Hello world\n");
    std::cout << var.getOne();

    var = ob.test("Good bye\n");
    std::cout << var.getOne();
}

See a live demo in godbolt.org
以下内容,请交给OP:

  • 我已经调整了一些原始代码,如Vector3dgetObject<T>()等。
  • 可以有一些以上所做的更多的改进,如演绎指南或重新安排一些代码的一部分,如果有效的。
xuo3flqw

xuo3flqw2#

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> {};
};

使用变量的另一个版本:

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};
};
tkqqtvp1

tkqqtvp13#

我并不真正了解您的使用情形,但要回答以下问题:可以将成员函数用作模板的非类型参数。下面的代码演示了其语法:

#include <iostream>

class foo {
    int bar_;
public:
    void setBar(int n = 0) {
        bar_ = n;
    }
    int getBar() const {
        return bar_;
    }
};

template<typename T, void(T::*F)(int)>
class accessor {
    T& accessee_;
public:
    accessor(T& a) : accessee_(a) {};
    T& setMember(int n) {
        auto& obj = accessee_;
        (obj.*F)(n);
        return obj;
    }
};

int main()
{
    foo a_foo;
    accessor<foo, &foo::setBar> foo_accessor(a_foo);
    foo& ref_to_a_foo = foo_accessor.setMember(42);
    std::cout << ref_to_a_foo.getBar() << "\n";
}

相关问题