是否有任何內置的C 機制提供自動生成代碼的能力,以便在類的每個成員上呼叫函式或運算子?
例如,如果我們有數百種型別需要使用一組特定的函式或運算子。而在每個型別中,每個型別都需要為其所有成員呼叫相同的函式或運算子(僅此而已)。
對于一些具體的例子,我們可以說這些型別有函式Save()和Load(),或者流運算子<<和>>。當TYPE::Save(stream s)被呼叫時,我們怎樣才能自動執行A.Save(s) B.Save(s) C.Save(s)? 如果代碼只是簡單地將執行力傳遞給所有成員,是否有任何方法可以使這個程序自動化?
下面是一個將被自動生成的一些代碼的例子(只有Save()函式)。編輯注:這個例子顯示所有3個成員都是同一型別,但是這個解決方案應該適用于任何型別組合的成員,只要它們都共享相關的函式/操作器
class TYPE
{
protected:
XTYPE A、B、C。
public:
void Save(stream s)
{
A.Save( s )。
B.Save( s );
C.Save( s );
}
};
我的一個舊引擎使用了瘋狂的回圈宏來完成這個任務。這使得使用宏來構建型別變得更加容易(當有數以百計的類使用它們的時候),而且產生的類也不難理解,但宏本身是混亂的,而且過于復雜。我希望有更多的東西......內置于語言中。
uj5u.com熱心網友回復:
正如P Kramer所提到的,可能有一些反射技巧你可以使用。另一個選擇是嘗試減少你要寫的代碼量。一個技巧是創建一個lambda,它接收一個引數包,并使用折疊運算式對引數包中的每個專案進行一些操作,就像這樣:
void Save(stream s)
{
[&](auto&& ... members) {
(members.Save(s), ...) 。
} (A, B, C);
}
即使A、B和C有不同的型別,只要它們都有一個Save()成員函式,上述方法也是可行的。
你也可以用常規的模板函式而不是lambdas來完成這個任務,但是上面的方法是最簡短的寫法。它仍然需要你列出所有你想應用該函式的成員變數的名字,你可以考慮將其放在一個宏中:
#define MEMBERS A, B, C
class TYPE
{
protected:
XTYPE MEMBERS。
public:
void Save(stream s)
{
[&](auto&& ... members) {
(members.Save(s), ...) 。
} (MEMBERS)。
}
};
受Vincent回答的啟發,你也可以添加一個函式,回傳一個std::tuple對成員變數的參考,然后可以使用std::apply和上述lambda進行遍歷:
class TYPE
{
protected:
XTYPE A、B、C。
auto Members()
{
return std::forward_as_tuple(A, B, C)。
}
public:
void Save(stream s)
{
std::apply([&](auto&& ... members) {
(members.Save(s), ...) 。
}, Members())。
}
};
稍微不那么靈活,但代碼更加緊湊的做法是創建一個成員函式,該函式以一個引數為基礎,并將該函式應用于所有成員:
class TYPE
{
protected:
XTYPE A、B、C。
void ApplyToMembers(auto&& func)
{
[&](auto&& ... members) {
(func(members), ...) 。
} (A, B, C);
}
public:
void Save(stream s)
{
ApplyToMembers([&](auto&& member){ member.Save(s); })。
}
};
uj5u.com熱心網友回復:
這確實是一種面向物件的方法。你可以使用一種叫做Iterator模式的設計模式。它基本上給了TYPE一個名為 "Iterator "的介面,實作了hasNext()和next()。然后你會把XTYPE放入一個vector<XTYPE>并在每個上執行。
class Iterator {
virtual boolean hasNext() const= 0;
virtual XTYPE *next()=0;
};
class TYPE: public Iterator
{
private:
size_t pos;
protected:
vector<XTYPE> XTYPES。
public:
void Save(stream s)
{
for (auto & XT : XTYPES ) {
XT.Save(s)。
}
}
virtual boolean hasNext() const {
if (pos => XTYPES.size( ) ) {
return false;
}
};
virtual XTYPE *next() {
return XTYPES[pos ]。
}
};
基本上,你必須以這樣或那樣的方式確保你想呼叫的型別有一些方法到你想呼叫的組。你也可以保持A, B, C不變,只是在迭代器類中制作一個指向每個XTYPE的指標向量。像這樣:
class Iterator {
virtual boolean hasNext() const= 0;
virtual XTYPE *next()= 0;
protected:
int pos;
向量<XTYPE*> XTYPES_ITER。
};
class TYPE: public Iterator
{
protected:
XTYPE A, B, C;
public:
Type() {
XTYPES_ITER = {&A, &B, &C};
}
void Save(stream s)
{
for (auto XT : XTYPES_ITER ) {
XT->Save(s)。
}
}
};
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/310489.html
標籤:
