假设我目前有以下代码:
double P[2][2][10];
std::vector<double> b, r, n;
//
// Assume that 10 doubles are pushed to each vector and
// that P has all its allocated values set.
//
for(int t=0; t<10; ++t) {
P[0][0][t] = b[t]*r[t]+n[t];
P[0][1][t] = b[t]*2.0*r[t]+(1.0-n[t]);
P[1][0][t] = b[t]*b[t]+r[t]*n[t];
P[1][1][t] = r[t]+n[t];
}
这是一个简单的例子来说明我的问题。在实际情况中,P
通常为P[9][9][100]
,方程式会更加混乱。我的问题是,基本上,我如何使用宏来使这些方程更具可读性?
特别是,这是一个非工作代码片段,用于说明我希望这个问题的解决方案看起来如何:
#define P(i,j) P[i][j][t]
#define b b[t]
#define r r[t]
#define n n[t]
for(int t=0; t<10; ++t) {
P(0,0) = b*r+n;
P(0,1) = b*2.0*r+(1.0-n);
P(1,0) = b*b+r*n;
P(1,1) = r+n;
}
此代码片段至少存在一个问题。例如,它将根据宏定义扩展For循环语句中的“r”和“n”。但你明白了。
这里的目标是开发一种输入方程式的方法,可以更容易地读取和检查错误。我对非宏解决方案持开放态度,虽然在我看来宏可能对此有所帮助。
关于我上面发布的非工作代码片段,以说明我想象一个解决方案可能看起来......是否可以使用宏,只有在For-loop体内才会发生宏替换?或者至少在之后 For循环语句?
答案 0 :(得分:2)
一个有效的解决方案是在for
之前定义所有宏,然后在for之后定义#undef
所有宏。例如:
#define P(i,j) P[i][j][t]
#define b b[t]
#define r r[t]
#define n n[t]
for(int t=0; t<10; ++t) {
P(0,0) = b*r+n;
P(0,1) = b*2.0*r+(1.0-n);
P(1,0) = b*b+r*n;
P(1,1) = r+n;
}
#undef P
#undef b
#undef r
#undef n
在我看来,宏不是这个问题的最佳解决方案,但我找不到任何其他解决方案。
答案 1 :(得分:2)
将概念上不同的东西分开通常是一个好主意。这通常可以提高代码清晰度,可维护性和灵活性。
这里至少有两件不同的事情:
循环遍历数据数组。
你计算了一些东西。
你能做的最好的事情就是把这些东西分成不同的功能,或者更好的是,类。这样的事情可以做到:
class MyFavoriteMatrix
{
private:
double m_P[2][2];
public:
MyFavoriteMatrix( double b, double r, double n ) {
m_P[0][0] = b*r+n;
m_P[0][1] = b*2.0*r+(1.0-n);
m_P[1][0] = b*b+r*n;
m_P[1][1] = r+n;
}
double Get( int i, int j ) {
return m_P[i][j];
}
}
然后你的循环看起来像这样:
for(int t = 0; t < 10; ++t)
{
// Computation is performed in the constructor
MyFavoriteMatrix mfm( b[t], r[t], n[t] );
// Now put the result where it belongs
P[0][0][t] = mfm.Get( 0, 0 );
P[0][1][t] = mfm.Get( 0, 1 );
P[1][0][t] = mfm.Get( 1, 0 );
P[1][1][t] = mfm.Get( 1, 1 );
}
注意这些解决方案:
如果您改变主意关于存储容器(例如,如Mark B建议的那样,出于性能原因将P [2] [2] [10]更改为P [10] [2] [2] ,你的计算代码根本不会受到影响,只有相对简单的循环会有所改变。
如果您需要在10个不同的地方执行相同的计算,则无需复制计算代码:您只需在那里调用MyFavoriteMatrix。
你发现计算代码需要改变你只需要在一个地方修改它:在MyFavoriteMatrix构造函数中。
每段代码看起来都很整洁,因此错字率很低。
所有你通过分离概念上不同的东西得到的 - 计算和迭代。
答案 2 :(得分:1)
这里有好的老式循环局部变量有什么问题?我假设你把你的向量称为比b
更有意义的东西,所以我会给它们稍长的名字。我还冒昧地在你非常密集的方程式中添加了一些清晰的空格:
double P_arr[10][2][2];
std::vector<double> b_arr, r_arr, n_arr;
//
// Assume that 10 doubles are pushed to each vector and
// that P has all its allocated values set.
//
for(int t = 0; t < 10; ++t)
{
const double b = b_arr[t];
const double r = r_arr[t];
const double n = n_arr[t];
double** P = P_arr[t];
P[0][0] = b * r + n;
P[0][1] = b * 2.0 * r + (1.0 - n);
P[1][0] = b * b + r * n;
P[1][1] = r + n;
}
答案 3 :(得分:1)
惊讶没有人建议使用参考文献。 http://en.wikipedia.org/wiki/Reference_(C%2B%2B)
typedef double Array22[2][2]; // for convenience...
for(int t = 0; t < 10; ++t)
{
const double &b(b_arr[t]);
const double &r(r_arr[t]);
const double &n(n_arr[t]);
Array22 &P(P_arr[t]);
P[0][0] = b * r + n;
P[0][1] = b * 2.0 * r + (1.0 - n);
P[1][0] = b * b + r * n;
P[1][1] = r + n;
}
答案 4 :(得分:0)
这是运营商设计的帮助。以下是add和multiply运算符的示例。您仍然需要根据需要添加其他内容。
#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>
std::vector<int>& operator+(std::vector<int>& a, std::vector<int>& b) {
std::transform (a.begin(), a.end(), b.begin(), a.begin(), std::plus<int>());
return a;
}
std::vector<int>& operator*(std::vector<int>& a, std::vector<int>& b) {
std::transform (a.begin(), a.end(), b.begin(), a.begin(), std::multiplies<int>());
return a;
}
int main() {
int a[6] = {1,2,3,4,5,6};
int b[6] = {6,7,8,9,10,11};
std::vector<int> foo(a, a+6);
std::vector<int> bar(b, b+6);
foo = foo + bar;
std::cout << foo[0] <<std::endl;
}