模板成员变量

che*_*erd 5 c++ templates member-variables

考虑以下两个类:

class LunchBox
{
  public:
    std::vector<Apple> m_apples;
};
Run Code Online (Sandbox Code Playgroud)

class ClassRoom
{
  public:
    std::vector<Student> m_students;
};
Run Code Online (Sandbox Code Playgroud)

这些类是相似的,因为它们都包含对象的成员变量向量; 然而,它们是不相似的,因为向量的对象是不同的,并且成员变量具有不同的名称.

我想写一个模板,它接受LunchBoxClassRoom作为模板参数(或其他一些参数)和相同类型的现有对象(类似于a std::shared_ptr).模板将返回一个对象,该对象添加了一个getNthElement(int i);成员函数以改进对方法的访问.用法如下:

// lunchBox is a previously initialized LunchBox
// object with apples already pushed into m_apples
auto lunchBoxWithAccessor = MyTemplate<LunchBox>(lunchBox);
auto apple3 = lunchBoxWithAccessor.getNthElement(3);
Run Code Online (Sandbox Code Playgroud)

我想这样做而不为每个类编写模板特化(这可能需要指定成员变量以某种方式操作).最好,我不想修改LunchBoxClassRoom类.写这样的模板有可能吗?

Ben*_*igt 5

您可以最小化必须为每个类编写的代码量 - 它不必是模板专门化,也不必是整个类.

class LunchBox
{
  public:
    std::vector<Apple> m_apples;
};

class ClassRoom
{
  public:
    std::vector<Student> m_students;
};

// you need one function per type, to provide the member name
auto& get_associated_vector( Student& s ) { return s.m_apples; }
auto& get_associated_vector( ClassRoom& r ) { return r.m_students; }

// and then the decorator is generic
template<typename T>
class accessor_decorator
{
     T& peer;
public:
     auto& getNthElement( int i ) { return get_associated_vector(peer).at(i); }

     auto& takeRandomElement( int i ) { ... }

     // many more ways to manipulate the associated vector

     auto operator->() { return &peer; }
};

LunchBox lunchBox{};
accessor_decorator<LunchBox> lunchBoxWithAccessor{lunchBox};
auto apple3 = lunchBoxWithAccessor.getNthElement(3);
Run Code Online (Sandbox Code Playgroud)

理想情况下,简单的辅助函数重载应该与类型在同一名称空间中,以使依赖于参数的查找工作(也称为Koenig查找).

如果您愿意,也可以在构造点指定成员:

template<typename T, typename TMemberCollection>
struct accessor_decorator
{
     // public to make aggregate initialization work
     // can be private if constructor is written
     T& peer;
     TMemberCollection const member;

public:
     auto& getNthElement( int i ) { return (peer.*member).at(i); }

     auto& takeRandomElement( int i ) { ... }

     // many more ways to manipulate the associated vector

     auto operator->() { return &peer; }
};

template<typename T, typename TMemberCollection>
auto make_accessor_decorator(T& object, TMemberCollection T::*member)
     -> accessor_decorator<T, decltype(member)>
{
    return { object, member };
}

LunchBox lunchBox{};
auto lunchBoxWithAccessor = make_accessor_decorator(lunchBox, &LunchBox::m_apples);
auto apple3 = lunchBoxWithAccessor.getNthElement(3);
Run Code Online (Sandbox Code Playgroud)