2015-11-13 52 views
3

我有一個包含其他結構以及基本數據類型的結構。我希望能夠通過模板函數訪問每個成員,包括主結構中包含的結構成員。訪問結構成員的模板函數

例如:

struct B { 
    int y; 
    int z; 
}; 

struct A { 
    int x; 
    B b; 
}; 

template <typename TMember> 
bool doSomething(A *a, TMember member) { 

    a->*member = 5; // some code accessing member 

} 

// Then access it with: 

doSomething(&myA, &A::x); 

// and likewise 

doSomething(&myA, &A::b.y); 

但是第二個將不能編譯,並拋出一個「對象參考失蹤」的錯誤。我認爲它是因爲A沒有成員b.y?

反正是有得到,我想還是會編碼不同的功能需要的功能?

(請注意,這只是一個例子,我有包含較大的結構,一定會來救我的不僅僅是寫第二功能更多的時間碼。)

謝謝!

+2

你肯定第一個編譯?當然,模板演繹會認爲它是一個int,但它仍然試圖訪問一個非靜態成員。 – Aesthete

+0

我認爲你不能做你想做的事。你將不得不編寫另一個函數。不知道你在做什麼或看到你的'結構'我的直覺反應是這樣的設計是不正確的,應該重新考慮。 – pstrjds

+0

「我希望能夠訪問每個成員,包括主結構中包含的結構的成員」。這將違反德米特法。別。 –

回答

1

一個簡單的方法來實現那就是使用函數指針作爲參數傳遞給你的模板函數:

// Example program 
#include <iostream> 
#include <string> 

struct B{ 
    int y; 
    int z; 
}; 

struct A{ 
    int x; 
    B b; 
}; 

int& get1(A& a) { return a.x; } 
int& get2(A& a) { return a.b.y; } 

template <typename T> 
bool doSomething(A *a, T& (*getter)(A&)){ 

    T& attr = (*getter)(*a); // get reference to the attribute 
    attr = 5; // modify the attribute 
    return true; 
} 


int main() 
{ 
    A myA; 

    doSomething(&myA, &get1); 
    doSomething(&myA, &get2); 
} 
+0

這實際上是我需要的一個很好的選擇。乾杯! –

2

有一對夫婦的問題在那裏。

較容易的一個是A::x的格式不正確:你想一個指向一個成員,而且需要地址的運營商。 doSomething(&myA, &A::x)會正常工作。

第二個是棘手的,因爲有一個在C中沒有辦法++,以形成一個指向一個構件的一個構件。除非你想用offsetof做類似hacky的非類型安全的東西,否則你需要比指針更強大的東西。舉例來說,你可以通過在返回成員的引用拉姆達:

template <typename TAccessor> 
void doSomething(A *a, TAccessor accessor){ 

    accessor(a) = 5; 
} 

int main() 
{ 
    A myA; 
    doSomething(&myA, [](A* a)->int&{ return a->b.y; }); 
} 

顯然是極不理想的東西,可讀性明智的。

編輯:哦,如果你的最終解決方案是基於成員的指針,以101010的建議,使模板參數專門成員指針模板參數。它不僅可能更高效,而且更自我記錄,如果你搞砸了,編譯器錯誤將會更加清晰十倍。

+0

有道理。我認爲爲了可讀性,我只會寫一些額外的功能。謝謝你的幫助! –

0

在你的榜樣,你在成員引用缺少&。 A :: b.y是未解決的問題。 A :: b :: y和A :: B :: y也不好。你可以使用B :: y。

doSomething(&myA, &B::y); 

但它不是一個成員,這可能會導致錯誤的行爲。或者可能不。因此,考慮

template <class TOwner, typename TMember> 
bool doSomething(TOwner * owner, TMember member); 

而且更換,我沒有看到你的代碼中的任何std::atomic。你是指整型而不是原子嗎?

+0

對不起,我忘了&,而且我的意思是整體。現在更新我的文章謝謝! –

1

你不能讓一個指針的指針到成員(這是forbidden by the language)。但是,您可以繼續訪問指向成員的指針。

如果我們概括的後果就是調用成員指針遞歸函數訪問:

template <typename C, typename T> 
decltype(auto) access(C& cls, T C::*member) { 
    return (cls.*member); 
} 

template <typename C, typename T, typename... Mems> 
decltype(auto) access(C& cls, T C::*member, Mems... rest) { 
    return access((cls.*member), rest...); 
} 

然後,我們可以寫doSomething採取指針的任意量:

template <typename... Members> 
void doSomething(A *a, Members... mems) { 
    access(*a, mems...) = 5; 
} 

,並調用它:

A myA; 
doSomething(&myA, &A::x); 
doSomething(&myA, &A::b, &B::y); 
+0

這個答案必須注滿! – 101010

0

你可以做你想要的類成員var iables通過傳遞指針的成員變量如下圖所示:

template <typename T> 
void doSomething(A *a, T A::*member){ 
    a->*member = 5; 
} 

LIVE DEMO