C++元编程的最佳实践:逻辑流
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++)中是否有任何功能允许该逻辑只写一次?也许有人能用lambdas做这件事吗?
我看到的方法是编写回调函数。所以你可以写一次逻辑部分,就像你在第二个文本块中写的一样。您还可以定义函数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
}
}
如果NO有意义,那么欢迎您加入我们这些与函数指针作斗争的大军。再次,我想说,你应该只写两个单独的函数,因为你可以看到这会变得多么丑陋。
作为免责声明,我没有编译此代码。我正在工作,这些机器上没有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占位符。实际工作是在每个类的运算符()成员函数中完成的。
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);
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 有一个打印语句的函数是一种糟糕的编程实践吗
- 在c代码之间共享数据的最佳方式
- 使用std::source_location报告错误的最佳实践
- 派生类销毁的最佳实践是什么
- 我是C++编程的新手,这些代码之间有什么区别,我应该使用哪一个
- 将寄存器设计成可由C和C++访问的外设的最佳实践
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 使用元编程技术找到最佳匹配
- 通过 vps 通过 FTP/SSH 远程编程C++的最佳方式
- 在FriendlyARM板mini2440中编程GPIO的最佳方式是什么
- C++元编程的最佳实践:逻辑流
- 将C#系统转换为跨平台应用程序的最佳编程语言
- 以编程方式选择 OpenCL 中最佳 GPU 的最佳方法是什么?
- 游戏编程最佳实践,课堂内外运动
- 最佳编程实践,C++标题和Include
- 在安卓上进行实时图形编程的最佳语言是什么?
- 泛型/模板编程最佳做法:限制类型,或不限制类型