使用成員指針可以實現代理類型,通過它可以查看一個對象的容器,通過它的一個成員(請參閱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