English 中文(简体)
D.R.Y 诉“避免宏观”
原标题:D.R.Y vs "avoid macros"
  • 时间:2009-10-12 14:28:25
  •  标签:

我正在利用Windows AP在C++中自行实施XUL。 这些要素是由XML教区建造的,这就要求这些教区具有相同的接口,因此我们无需为每个单元的建筑商撰写习惯法。 其结果是,我的大多数成员认为:

class Button : public Element
{
public:
    static const char * Type() { return "button"; }

private:
    friend class Element;
    Button(Element * inParent, const AttributesMapping & inAttributesMapping);
};


class Label : public Element
{
public:
    static const char * Type() { return "label"; }

private:
    friend class Element;
    Label(Element * inParent, const AttributesMapping & inAttributesMapping);
};


class Description : public Element
{
public:
    static const char * Type() { return "description"; }

    virtual bool init();

private:
    friend class Element;
    Description(Element * inParent, const AttributesMapping & inAttributesMapping);
};

因此,这里有许多法典上的重复。 我想知道,用宏观呼吁来取代这些呼吁是否是一个好的想法:

#define DECLARE_ELEMENT(ElementType, XULName)           
class ElementType : public Element                      
{                                                       
public:                                                 
    static const char * Type() { return XULName; }      
                                                        
private:                                                
    friend class Element;                               
    ElementType(                                        
        Element * inParent,                             
        const AttributesMapping & inAttributesMapping); 
};                                                      


DECLARE_ELEMENT(Window, "window")
DECLARE_ELEMENT(Button, "button")
DECLARE_ELEMENT(Label, "label")

我没有完全阐述这一概念,因此,这里缺少一些东西,如类别定义,以及(可能)每个要素增加方法的能力。

但是,我很想知道你对在这种情况下使用宏观方法的看法。 自由地表达你们的想法。

http://www.ohchr.org。

现在,我使用的是小幅手法,从一套模板中生成来源和主人档案。 我加强了文字,以便档案也自动在SVN上添加标记,并修改了视频演播室项目档案,以包括档案。 这为我节省了大量手工劳动。 我对这一解决办法感到非常高兴。 此时此刻,正是模板所看的:

#ifndef {{ELEMENT_NAME_UPPER}}_H_INCLUDED
#define {{ELEMENT_NAME_UPPER}}_H_INCLUDED


#include "XULWin/Element.h"


namespace XULWin
{

    class {{ELEMENT_NAME}} : public Element
    {
    public:
        static ElementPtr Create(Element * inParent, const AttributesMapping & inAttr)
        { return Element::Create<{{ELEMENT_NAME}}>(inParent, inAttr); }

        static const char * Type() { return "{{ELEMENT_TYPE}}"; }

        virtual bool init();

    private:
        friend class Element;
        {{ELEMENT_NAME}}(Element * inParent, const AttributesMapping & inAttributesMapping);
    };

} // namespace XULWin


#endif // {{ELEMENT_NAME_UPPER}}_H_INCLUDED

CPP文件:

#include "XULWin/{{ELEMENT_NAME}}.h"
#include "XULWin/{{ELEMENT_NAME}}Impl.h"
#include "XULWin/AttributeController.h"
#include "XULWin/Decorator.h"


namespace XULWin
{

    {{ELEMENT_NAME}}::{{ELEMENT_NAME}}(Element * inParent, const AttributesMapping & inAttributesMapping) :
        Element({{ELEMENT_NAME}}::Type(),
                inParent,
                new {{ELEMENT_NAME}}Impl(inParent->impl(), inAttributesMapping))
    {
    }


    bool {{ELEMENT_NAME}}::init()
    {
        return Element::init();
    }

} // namespace XULWin
最佳回答

我在此不使用宏观方法。 标签属于“说明”类,其额外成员职能是<条码>,其他成员不使用。 因此,你无法使用宏观来界定这一定义,但你却以人工方式扩大宏观范围并增加外线。

对我来说,这比仅仅写出所有类别定义就更违反了南联盟。 A 几乎不重复计算,而只重复处理一个案件,往往更难以维持这种重复循环。 南斯拉夫联邦共和国正在寻找好的摘要,而不仅仅是在碎块上cutting。

我可以替换这些建筑商,但用<代码>SetAttributes功能在<代码>Element 上。 这可能减少每个衍生产品类别实际需要的碎块数量,因为建筑商是从基地继承的一件事。 但这取决于每一类的构造者是如何类似的。

问题回答

如果你使用模板解决办法,你可以避免宏观因素和<>m>,避免重复:

template <const char *XULName>
class ElementType : public Element
{
public:
    static const char * Type() { return XULName; }

private:
    friend class Element;
    ElementType(
        Element * inParent,
        const AttributesMapping & inAttributesMapping);
};

char windowStr[]="window";
char buttonStr[]="button";
char labelStr[]="label";

typedef ElementType<windowStr> Window;
typedef ElementType<buttonStr> Button;
typedef ElementType<labelStr> Label;

th: 模版只能用于C所需的宏观产品。

执行说明:由于字面上存在内部联系,因此,你需要<代码>windowStr。 实际上,您希望在H文档中公布windowStrbuttonStr.labelStr的声明,以及在CPP档案中对这些指示的定义。

作为一种替代办法,你可以考虑制定一部单独的建筑步骤,而不是使用加工剂。 见cog。 但你可以使用你喜欢的东西。 这样,你们就能够全面控制产生的东西。 (Macros是强势的,但仅限于你所能做的事情。)

我认为,宏观办法可以减少重复性(从而减少出现错误的风险)的低水平。

宏观方法的使用仍将非常地方化,应当使整个守则更容易理解。 当然,这也可能需要一些文件工作。

无论怎样使用,该守则都更加简单。

南盟和避免马科罗这两个目标相同:使你的法典更加简单。

  • DRY: avoid repetition
  • Avoid Macro: because they can introduce hard to diagnose compiler errors or hard to diagnose bugs (as they bypass namespace boundaries and are not C++ aware / typesafe).

因此,与准则一样,我建议遵循精神而不是文字。 在你看来,似乎很明显,宏观将实际简化你的法典,因此,你可能应当加以利用。

然而,考虑到宏观因素可能带来的问题,确保安全地命名。 在开始时列入项目名称/名称,例如减少与现有宏观冲突的可能性。

(你可以看望BOOST的警卫,了解命名公约的想法)

如果你计划使用自动编码文件工具,如氧气,则使用替代<代码>}/代码>定义的宏观方法。 在生成任何文件之前,你必须先通过加工商操作该守则。 也许不是最重要的考虑,而是需要考虑的问题。

IMHO这一宏观是合理的。 虽然我认为最好添加<条码>第11条之规定——ELEMENT,以防ling宏观。 (除非你计划在其他档案中使用这一宏观方法)

但请注意,只有这些班级永远不会差别很大(或最多)。


还有一个使用模板的解决办法。 考虑采用以下守则:

namespace impl
{
    struct ButtonTag;
    struct LabelTag;


    template< typename TypeTag >
    struct NameGenerator;

    template<>
    struct NameGenerator< ButtonTag >
    {
        static const char * getName() { return "button"; }
    };

    template<>
    struct NameGenerator< LabelTag >
    {
        static const char * getName() { return "label"; }
    };


    template< typename TypeTag >
    class SimpleElement : public Element
    {
    public:
        static const char * Type()
        { return NameGenerator< TagType >::getName(); }

    private:
        friend class Element;

        SimpleElement(
            Element * inParent,
            const AttributesMapping & inAttributesMapping);

    };
}

typedef impl::SimpleElement< impl::ButtonTag > Button;
typedef impl::SimpleElement< impl::LabelTag > Label;

然而,它比宏观更有利。

编码样本

enum Types { BUTTON, LABEL,...}

struct TypeList {
    static const char * Type(const int nID)
    {
         switch(nID) {
         case BUTTON: return "button";
         ...
    }
};

template<ID>
class IElem : public Element
{
private:
    static TypeList m_oTypeList;

public:
    static const char * Type() { return m_oTypeList.Type(ID); }
private:
friend class Element;
    IElem(Element * inParent, const AttributesMapping & inAttributesMapping)
    {...}
};

一般事务/其他职等

class Button : public IElem<BUTTON>
{
...
}

我甚至可以更进一步,在使用宏观产品时,可以同时使用单一散射和双壳。 单一散射线会形成固定不变,并形成双重加固的识别特征,以建立新的组合。

#define DECLARE_ELEMENT(ElementType)                     
class C ## ElementType : public Element                  
{                                                        
public:                                                  
    static const char * Type() { return # ElementType; } 
                                                         
private:                                                 
    friend class Element;                                
    C ## ElementType(                                    
        Element * inParent,                              
        const AttributesMapping & inAttributesMapping);  
}

DECLARE_ELEMENT(window); // defines Cwindow
DECLARE_ELEMENT(button); // defines Cbutton
DECLARE_ELEMENT(label);  // defines Clabel

例如,下面的法典是我有时为了测试某些共同类型的规模而写的。

#include <stdio.h>

#define OUT( _type ) printf("sizeof(%s) = %d
", #_type, sizeof(_type))

int main() {
  OUT( char );
  OUT( int );
  OUT( short );
  OUT( long );
  OUT( long long );
  OUT( void* );
  return 0;
}

我将对这一案例进行宏观表决。 他们肯定说,毕竟是坏的,你不应试图与他们一道书写行文,但不是好事。

我认为,在这种情况下,使用宏观方法是站不住脚的,但只有你才能这样做。

  • can develop a solution that is not too complex but covers (preferably) all necessary Element class structures
  • document the macro well
  • are aware that some IDEs have problems with macro-generated class structures and can live with the consequences

该法典在“





相关问题