使用成员指针可以实现代理类型,通过它可以查看一个对象的容器,通过它的一个成员(请参阅pointer to data member)或其中一个获得者(请参阅pointer to member function)代替每个对象。第一种解决方案只涉及数据成员,而第二种解决方案则涉及两者
容器必须知道使用哪个容器以及要映射哪个成员,哪些成员将在施工时提供。指向成员的指针的类型取决于该成员的类型,因此它必须被视为一个附加的模板参数。
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
private:
const Container * m_container;
MemberPtr m_member;
};
接下来,实施operator[]
操作,既然你提到这是你如何想访问你的元素。首先解除引用成员指针的语法可能会令人惊讶。
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
// Dispatch to the right get method
auto operator[](const size_t p_index) const
{
return (*m_container)[p_index].*m_member;
}
private:
const Container * m_container;
MemberPtr m_member;
};
要使用这个实现,你会写是这样的:
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
virtual_vector<decltype(printme), decltype(&Elem::a)> X(printme, &Elem::a);
print_in_order(order, X);
}
这是一个有点麻烦,因为没有模板参数推导发生。因此,让我们添加一个免费函数来推断模板参数。
template<class Container, class MemberPtr>
virtual_vector<Container, MemberPtr>
make_virtual_vector(const Container & p_container, MemberPtr p_member_ptr)
{
return{ p_container, p_member_ptr };
}
的使用变为:
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
auto X = make_virtual_vector(printme, &Elem::a);
print_in_order(order, X);
}
如果你想支持成员函数,这是一个稍微复杂一些。首先,解引用数据成员指针的语法与调用函数成员指针略有不同。您必须实现operator[]
的两个版本,并根据成员指针类型启用正确的版本。幸运的是,该标准提供了std::enable_if
和std::is_member_function_pointer
(均在<type_trait>
标题中),这允许我们做到这一点。成员函数指针要求你指定要传递给函数的参数(在本例中为非),以及表达式周围的额外括号,这些括号会评估为要调用的函数(参数列表之前的所有内容)。
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
// For mapping to a method
template<class T = MemberPtr>
auto operator[](std::enable_if_t<std::is_member_function_pointer<T>::value == true, const size_t> p_index) const
{
return ((*m_container)[p_index].*m_member)();
}
// For mapping to a member
template<class T = MemberPtr>
auto operator[](std::enable_if_t<std::is_member_function_pointer<T>::value == false, const size_t> p_index) const
{
return (*m_container)[p_index].*m_member;
}
private:
const Container * m_container;
MemberPtr m_member;
};
为了测试这一点,我添加了一个getter到Elem
类,用于说明目的。
struct Elem {
int a, b;
int foo() const { return a; }
Elem(int a, int b) : a(a), b(b) {}
};
这里是它如何被使用:
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
{ // print member
auto X = make_virtual_vector(printme, &Elem::a);
print_in_order(order, X);
}
{ // print method
auto X = make_virtual_vector(printme, &Elem::foo);
print_in_order(order, X);
}
}
写自己的类,它包装一个向量和重载'[]'运营商? – imreal