什么是分解复杂表达式的好编码习惯用法?

时间:2014-05-06 22:34:21

标签: c++ idioms

我的问题是关于编码风格和C ++中复杂表达式的分解。

我的程序有一个复杂的类层次结构,由类等组成的类组成。许多程序的对象都持有指向其他对象的指针或索引。有一些名称空间。正如我所说,它很复杂 - 我的意思是它是一个非常典型的10,000行C ++程序。

出现了规模问题。我的代码开始有许多不可读的表达式,如p->a(b.c(r).d()).q(s)->f(g(h.i()))。 (正如我所说,这是不可读的。我无法阅读它,我就是那个写它的人!你可以只看它来捕捉心情。)我试过重写这样的表达式

{
    const I  ii = h.i();
    const G &gg = g(ii);
    const C &cc = b.c(r);
    // ..
    T *const qq = aa.q(s);
    qq->f(gg);
}

所有那些本地范围的符号可以说代码更具可读性,但我承认我并不关心整体风格。毕竟,一些本地符号是const &引用,而其他符号代表数据的副本。如果我不小心省略了&之一,从而调用了某个大对象的不必要副本,该怎么办?我的编译器几乎不会警告我。

此外,带有本地符号的版本是详细的。

两种解决方案都不适合。在C ++中是否存在更难惯用的,不易出错的方法来分解不可读的表达式?

例证

如果问题的最小,可编辑的说明有帮助,那么这里就是一个。

#include <iostream>

class A {
  private:
    int m1;
    int n1;
  public:
    int m() const { return m1; }
    int n() const { return n1; }
    A(const int m0, const int n0) : m1(m0), n1(n0) {}
};

class B {
  private:
    A a1;
  public:
    const A &a() const { return a1; }
    B(const A &a0) : a1(a0) {}
};

B f(int k) {
    return B(A(k, -k));
}

int main() {

    const B  &my_b = f(15);

    {
        // Here is a local scope in which to decompose an expression
        // like my_b.a().m() via intermediate symbols.
        const A  &aa = my_b.a();
        const int mm = aa.m();
        const int nn = aa.n();
        std::cout << "m == " << mm << ", n == " << nn << "\n";
    }

    return 0;

}

其他信息

我怀疑它与问题有关,但如果是:我的程序定义了几个模板,但目前不使用任何运行时多态。

实际示例

其中一位评论者请求我的代码中的实际示例。这是:

bool Lgl::is_order_legal_for_movement(
    const Mb::Mapboard &mb, const size_t ix, Chains *const p_chns1
) {

    if (!mb.accepts_orders()) return false;
    const Basic_mapboard &bmb = mb.basic();
    if (!is_location_valid(bmb, ix, false)) return false;
    const Space            &x = mb.spc(ix);
    if (!x.p_unit()) return true;
    const size_t           cx = x.i_cst_occu();
    const Basic_space     &bx = x.basic();
    const Unit             &u = x.unit();
    const bool           army = u.is_army();
    const bool          fleet = u.is_fleet();
    const Order         order = u.order();
    const size_t           is = u.source();
    const Location         lt = u.target_loc();
    const size_t           it = lt.i_spc;
    const size_t           ct = lt.i_cst;
    // ...

    {   
        const Space        &s = mb.spc(is);
        const Basic_space &bs = s.basic();
        result = ( 
            (army_s && (
                bs.nbor_land(it) || count_chains_if(
                    Does_chain_include(ix), chns_s, false
                )   
            )) || (fleet_s && (
                // By rule, support for a fleet can name a coast,
                // but need not.
                ct == NO_CST
                ? is_nbor_sea_no_cst(bs, cs, it) 
                : is_nbor_sea       (bs, cs, lt) 
            ))  
        ) && is_nbor_no_cst(army, fleet, bx, cx, it);
    }   

    // ...

}

1 个答案:

答案 0 :(得分:1)

对于您的实际代码示例,我可以看到您为什么要使其更具可读性。我可能会重新编码:

if (army_s) {
    result = bs.nbor_land(it) || 
            count_chains_if(Does_chain_include(ix), chns_s, false);
} else if (fleet_s) {
    // By rule, support for a fleet can name a coast,
    // but need not.
    if (ct == NO_CST)
        result = is_nbor_sea_no_cst(bs, cs, it);
    else 
        result = is_nbor_sea(bs, cs, lt);
}
result &= is_nbor_no_cst(army, fleet, bx, cx, it);

它执行相同的逻辑,包括短路评估,但我认为对人类解释有点好。我还遇到过编译器,这些编译器也使用这种样式生成更好的代码,而不是原始代码包含的非常复杂的复合行。

希望有所帮助。