[英]Best practice C++ metaprogramming: logic flow
也許我被Ruby寵壞了,但是在我看來,如果我有兩個使用相同基本邏輯(但細節有所不同)的函數,則只需要編寫一次邏輯即可,因此,我只需要將代碼維護在一個地方。
這是基本邏輯,我在許多不同的功能中都重復使用了這些邏輯。 更改的部分標記為A,B,C,D,E和F。
if (recursions) {
while (lcurr || rcurr) {
if (!rcurr || (lcurr && (lcurr->key < rcurr->key))) {
// A
lcurr = lcurr->next;
} else if (!lcurr || (rcurr && (rcurr->key < lcurr->key))) {
// B
rcurr = rcurr->next;
} else { // keys are == and both present
// C
lcurr = lcurr->next;
rcurr = rcurr->next;
}
}
} else {
while (lcurr || rcurr) {
if (!rcurr || (lcurr && (lcurr->key < rcurr->key))) {
// D
lcurr = lcurr->next;
} else if (!lcurr || (rcurr && (rcurr->key < lcurr->key))) {
// E
rcurr = rcurr->next;
} else { // keys == and both left and right nodes present
// F
lcurr = lcurr->next;
rcurr = rcurr->next;
}
}
}
函數的返回值也可能不同。 如果可能的話,我希望能夠在其他地方也有其他邏輯。
我意識到這可以通過C宏來完成,但是它們似乎並不是特別可維護。 我還意識到,如果我的矩陣類型使用嵌套的STL列表,這可能會更容易。 但是C ++ 11(或舊的C ++)中是否有任何功能只能將此邏輯編寫一次? 可以用lambda做到這一點嗎?
我看到的完成方式是編寫回調函數。 因此,您只需編寫一次邏輯部分,就像在第二個文本塊中一樣。 您還將定義函數A,B,C,D,E和F。
在邏輯函數中,您將同時傳入所需的參數和指向回調函數的指針。 然后,在邏輯函數中,您將調用這些回調並將其需要的參數傳遞給它們。
老實說,這似乎最終將需要更多工作。 您將為邏輯維護一個真相,但函數指針可能會非常麻煩,並且會降低代碼的可讀性。
為了提供盡可能多的信息,示例:
int addTwoNumbers(int a, int b) { //A simple adding function
return a + b;
}
int subtractTwoNumbers(int a, int b) { //A simple subtracting function
return a - b;
}
/*
* This is the fun one. The first argument is a pointer to a function. The other
* arguments are the numbers to do math with. They aren't as important.
* The important part is that, so long as the function declaration matches the one here
* (so a function that returns an int and takes in two ints as arguments) it can be
* used by this function
*/
void math(int (*mathFunc)(int, int), int one, int two) {
cout << *mathFunc(one, two);
}
int main(int argc, char* argv[]) {
int whichMath = 0; //Assume 1 is add, 2 is subtract
if(whichMath == 1) {
math(&addTwoNumbers, 5, 6); //we're going to add 5 and 6
} else {
math(&subtractTwoNumbers, 5, 6); // we're going to subtract 5 and 6
}
}
如果那沒有道理,那么歡迎您加入我們中使用函數指針而奮斗的大軍。 同樣,我想說的是您應該只編寫兩個單獨的函數,因為您可以看到這將變得多么丑陋。
作為免責聲明,我尚未編譯此代碼。 我在工作,這些機器上沒有c ++編譯器。
我過去曾大量使用此站點作為功能指針的參考: http : //www.newty.de/fpt/fpt.html#defi
好的,一種解決方案是提取一些冗余代碼並將其放入模板中,例如
template<T1, T2, T3>
bool TESTKEYS(T1 lcurr, T2 rcurr, T3 actor)
{
while (lcurr || rcurr) {
if (!rcurr || (lcurr && (lcurr->key < rcurr->key))) {
if (actor.TestLeft(....)) return false;
lcurr = lcurr->next;
} else if (!lcurr || (rcurr && (rcurr->key < lcurr->key))) {
if (actor.TestRight(....)) return false;
rcurr = rcurr->next;
} else { // keys == and both left and right nodes present
if (actor.TestBoth(....)) return false;
lcurr = lcurr->next;
rcurr = rcurr->next;
}
}
return true;
}
您將需要自己決定要為TestLeft等使用哪些參數。
template<typename A, typename B, typename C>
void compute (/*some parameters */)
{
if (recursions) {
while (lcurr || rcurr) {
if (!rcurr || (lcurr && (lcurr->key < rcurr->key))) {
auto aResult = A (lcurr, rcurr);
lcurr = lcurr->next;
} else if (!lcurr || (rcurr && (rcurr->key < lcurr->key))) {
auto bResult = B (lcurr, rcurr);
} // ... and so on
C (aResult, bResult);
} // ... etc
}
要調用compute
,你需要寫你想傳遞下來的地方您的A到F占位符的類 。 實際工作在每個類的operator()成員函數中完成。
class A1 {
public:
double operator() (SomeType t1, SomeType t2) {
// do work
}
};
class A2 {
public:
int operator() (SomeType t1, SomeType t2) {
// do work
}
};
class B1 {
public:
char* operator() (SomeType t1, SomeType t2) {
// do work
}
};
class B2 {
public:
SomeClass* operator() (SomeType t1, SomeType t2) {
// do work
}
};
class C1 {
public:
int operator() (double t1, char* t2) {
}
class C2 {
public:
int operator() (int t1, SomeClass* t2) {
}
compute<A1, B1, C1>(whatever);
compute<A2, B2, C2>(whatever);
請注意,A1和B1返回類型如何與C1參數匹配,對於A2,B2和C2同樣。
auto
需要C ++ 11,如果無法使用它,則必須做一些額外的工作:
class A1 {
public:
typedef double result_type;
double operator() (SomeType t1, SomeType t2) {
// do work
}
};
和內部compute
typename A::result_type aResult = A (lcurr, rcurr);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.