2017-02-11 67 views
1

我所寻找的是,具有不流利类:什么是将非流畅接口“重新实现”为流畅接口的一种好方法?

class NonFluent { 
    int i=0; 
public: 
    void setValue(int i) {this->i = i;} 
    void multiplyValue(int i) {this->i *= i;} 
    int getValue() {return this->i;} 
}; 

我想改变void方法实际上到*this返回参考。我知道这是不可能的,因为我们不能只改变返回类型,因为C++将无法区分函数调用。

我们可以使用组成:

class Fluent { 
    Fluent& setValue(int i) {var.setValue(i); return *this;} 
    Fluent& multiplyValue(int i) {var.multiplyValue(i); return *this;} 
    int getValue() {return var.getValue();} 

private: 
    NonFluent var; 
}; 

但是,这是一个痛苦,如果有很多void方法开始。 我们也可以使用对象编辑器问我关于: Is Object Editor a good approach if there are multiple member functions to call?的问题,但它有很多缺点。

你知道有什么好方法可以做到吗? (不直接改变非流利级?)

回答

0

作为另一个答案,我采取了不同的方式,即导致最低代码追加:

编辑:

template <class T> 
struct EditorImpl 
{ 
    T* ptr; 

    template <class F> 
    EditorImpl& operator()(F&& f) 
    { 
     f(ptr); 
     return *this; 
    } 

    T* yield() const { 
     return ptr; 
    } 
}; 

template <class T> 
EditorImpl<T> Editor(T* ptr) { return EditorImpl<T>{ptr}; } 

template <class T> 
EditorImpl<T> Editor(T& ref) { return EditorImpl<T>{&ref}; } 

GET_MACRO(一切都高达100):

namespace detail { 
#define GET_MACRO_1(_1, NAME, ...) NAME 
#define GET_MACRO_2(_1, _2, NAME, ...) NAME 
#define GET_MACRO_3(_1, _2, _3, NAME, ...) NAME 
//... 
#define GET_MACRO_98(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, NAME, ...) NAME 
#define GET_MACRO_99(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, NAME, ...) NAME 
#define GET_MACRO_100(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, NAME, ...) NAME 
} 

宏产生的λ它调用对象宏参数:

namespace detail { 
#define E_1(_1)[](auto* p) {p -> _1; } 
#define E_2(_1,_2)[](auto* p) {p -> _1; p -> _2; } 
#define E_3(_1,_2,_3)[](auto* p) {p -> _1; p -> _2; p -> _3; } 
//...  
#define E_98(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98)[](auto* p) {p -> _1; p -> _2; p -> _3; p -> _4; p -> _5; p -> _6; p -> _7; p -> _8; p -> _9; p -> _10; p -> _11; p -> _12; p -> _13; p -> _14; p -> _15; p -> _16; p -> _17; p -> _18; p -> _19; p -> _20; p -> _21; p -> _22; p -> _23; p -> _24; p -> _25; p -> _26; p -> _27; p -> _28; p -> _29; p -> _30; p -> _31; p -> _32; p -> _33; p -> _34; p -> _35; p -> _36; p -> _37; p -> _38; p -> _39; p -> _40; p -> _41; p -> _42; p -> _43; p -> _44; p -> _45; p -> _46; p -> _47; p -> _48; p -> _49; p -> _50; p -> _51; p -> _52; p -> _53; p -> _54; p -> _55; p -> _56; p -> _57; p -> _58; p -> _59; p -> _60; p -> _61; p -> _62; p -> _63; p -> _64; p -> _65; p -> _66; p -> _67; p -> _68; p -> _69; p -> _70; p -> _71; p -> _72; p -> _73; p -> _74; p -> _75; p -> _76; p -> _77; p -> _78; p -> _79; p -> _80; p -> _81; p -> _82; p -> _83; p -> _84; p -> _85; p -> _86; p -> _87; p -> _88; p -> _89; p -> _90; p -> _91; p -> _92; p -> _93; p -> _94; p -> _95; p -> _96; p -> _97; p -> _98; } 
#define E_99(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99)[](auto* p) {p -> _1; p -> _2; p -> _3; p -> _4; p -> _5; p -> _6; p -> _7; p -> _8; p -> _9; p -> _10; p -> _11; p -> _12; p -> _13; p -> _14; p -> _15; p -> _16; p -> _17; p -> _18; p -> _19; p -> _20; p -> _21; p -> _22; p -> _23; p -> _24; p -> _25; p -> _26; p -> _27; p -> _28; p -> _29; p -> _30; p -> _31; p -> _32; p -> _33; p -> _34; p -> _35; p -> _36; p -> _37; p -> _38; p -> _39; p -> _40; p -> _41; p -> _42; p -> _43; p -> _44; p -> _45; p -> _46; p -> _47; p -> _48; p -> _49; p -> _50; p -> _51; p -> _52; p -> _53; p -> _54; p -> _55; p -> _56; p -> _57; p -> _58; p -> _59; p -> _60; p -> _61; p -> _62; p -> _63; p -> _64; p -> _65; p -> _66; p -> _67; p -> _68; p -> _69; p -> _70; p -> _71; p -> _72; p -> _73; p -> _74; p -> _75; p -> _76; p -> _77; p -> _78; p -> _79; p -> _80; p -> _81; p -> _82; p -> _83; p -> _84; p -> _85; p -> _86; p -> _87; p -> _88; p -> _89; p -> _90; p -> _91; p -> _92; p -> _93; p -> _94; p -> _95; p -> _96; p -> _97; p -> _98; p -> _99; } 
#define E_100(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99,_100)[](auto* p) {p -> _1; p -> _2; p -> _3; p -> _4; p -> _5; p -> _6; p -> _7; p -> _8; p -> _9; p -> _10; p -> _11; p -> _12; p -> _13; p -> _14; p -> _15; p -> _16; p -> _17; p -> _18; p -> _19; p -> _20; p -> _21; p -> _22; p -> _23; p -> _24; p -> _25; p -> _26; p -> _27; p -> _28; p -> _29; p -> _30; p -> _31; p -> _32; p -> _33; p -> _34; p -> _35; p -> _36; p -> _37; p -> _38; p -> _39; p -> _40; p -> _41; p -> _42; p -> _43; p -> _44; p -> _45; p -> _46; p -> _47; p -> _48; p -> _49; p -> _50; p -> _51; p -> _52; p -> _53; p -> _54; p -> _55; p -> _56; p -> _57; p -> _58; p -> _59; p -> _60; p -> _61; p -> _62; p -> _63; p -> _64; p -> _65; p -> _66; p -> _67; p -> _68; p -> _69; p -> _70; p -> _71; p -> _72; p -> _73; p -> _74; p -> _75; p -> _76; p -> _77; p -> _78; p -> _79; p -> _80; p -> _81; p -> _82; p -> _83; p -> _84; p -> _85; p -> _86; p -> _87; p -> _88; p -> _89; p -> _90; p -> _91; p -> _92; p -> _93; p -> _94; p -> _95; p -> _96; p -> _97; p -> _98; p -> _99; p -> _100; } 
} 

#define E_(...) GET_MACRO_100(__VA_ARGS__, E_100, E_99, E_98, E_97, E_96, E_95, E_94, E_93, E_92, E_91, E_90, E_89, E_88, E_87, E_86, E_85, E_84, E_83, E_82, E_81, E_80, E_79, E_78, E_77, E_76, E_75, E_74, E_73, E_72, E_71, E_70, E_69, E_68, E_67, E_66, E_65, E_64, E_63, E_62, E_61, E_60, E_59, E_58, E_57, E_56, E_55, E_54, E_53, E_52, E_51, E_50, E_49, E_48, E_47, E_46, E_45, E_44, E_43, E_42, E_41, E_40, E_39, E_38, E_37, E_36, E_35, E_34, E_33, E_32, E_31, E_30, E_29, E_28, E_27, E_26, E_25, E_24, E_23, E_22, E_21, E_20, E_19, E_18, E_17, E_16, E_15, E_14, E_13, E_12, E_11, E_10, E_9, E_8, E_7, E_6, E_5, E_4, E_3, E_2, E_1)(__VA_ARGS__) 

最终宏:

namespace detail { 
#define EDIT_0(_1)Editor(_1).yield() 
#define EDIT_1(_1,_2)Editor(_1)(E_(_2)).yield() 
#define EDIT_2(_1,_2,_3)Editor(_1)(E_(_2,_3)).yield() 
#define EDIT_3(_1,_2,_3,_4)Editor(_1)(E_(_2,_3,_4)).yield() 
//... 
#define EDIT_98(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99)Editor(_1)(E_(_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99)).yield() 
#define EDIT_99(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99,_100)Editor(_1)(E_(_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99,_100)).yield() 
} 
#define EDIT(...) GET_MACRO_100(__VA_ARGS__, EDIT_99, EDIT_98, EDIT_97, EDIT_96, EDIT_95, EDIT_94, EDIT_93, EDIT_92, EDIT_91, EDIT_90, EDIT_89, EDIT_88, EDIT_87, EDIT_86, EDIT_85, EDIT_84, EDIT_83, EDIT_82, EDIT_81, EDIT_80, EDIT_79, EDIT_78, EDIT_77, EDIT_76, EDIT_75, EDIT_74, EDIT_73, EDIT_72, EDIT_71, EDIT_70, EDIT_69, EDIT_68, EDIT_67, EDIT_66, EDIT_65, EDIT_64, EDIT_63, EDIT_62, EDIT_61, EDIT_60, EDIT_59, EDIT_58, EDIT_57, EDIT_56, EDIT_55, EDIT_54, EDIT_53, EDIT_52, EDIT_51, EDIT_50, EDIT_49, EDIT_48, EDIT_47, EDIT_46, EDIT_45, EDIT_44, EDIT_43, EDIT_42, EDIT_41, EDIT_40, EDIT_39, EDIT_38, EDIT_37, EDIT_36, EDIT_35, EDIT_34, EDIT_33, EDIT_32, EDIT_31, EDIT_30, EDIT_29, EDIT_28, EDIT_27, EDIT_26, EDIT_25, EDIT_24, EDIT_23, EDIT_22, EDIT_21, EDIT_20, EDIT_19, EDIT_18, EDIT_17, EDIT_16, EDIT_15, EDIT_14, EDIT_13, EDIT_12, EDIT_11, EDIT_10, EDIT_9, EDIT_8, EDIT_7, EDIT_6, EDIT_5, EDIT_4, EDIT_3, EDIT_2, EDIT_1, EDIT_0)(__VA_ARGS__) 

实施例类:

class Simple { 
    int i=0; 
public: 
    Simple() : Simple(0) {} 
    Simple(int i) {this->i = i;} 
    void setValue(int i) {this->i = i;} 
    void multiplyValue(int i) {this->i *= i;} 
    void halve() {this->i /= 2;} 
    int getValue() {return this->i;} 

}; 

和所有的疯狂后,使用:

Simple* simple = EDIT(new Simple, setValue(50), multiplyValue(3)); 

这是最好的我可以做:)

2

更好的方法,你可以用Fluent使用,但不能与NonFluent,就是让你的类不变,并有其方法返回新对象与修改的结果:

class Fluent { 
    static Fluent withValue(int i) { 
     NonFluent v; 
     v.setValue(i); 
     return Fluent(v); 
    } 
    Fluent multiplyValue(int i) const { 
     Fluent res(var); 
     res.var.multiplyValue(i); 
     return res; 
    } 
    int getValue() const {return var.getValue;} 
private: 
    Fluent(const NonFluent& v) : var(v) {} 
    NonFluent var; 
}; 

注意静态工厂方法创建Fluent对象。

使用工厂的代码如下所示:

int res = Fluent 
    .withValue(5) 
    .multiplyValue(2) 
    .getValue(); 

这给你一个机会,返工API包括方法服用其他流利的对象,像这样:

Fluent multiply(const Fluent& other) const { 
    Fluent res(var); 
    res.var.multiplyValue(other.getValue()); 
    return res; 
} 

总的结果是您的API变得易于并发,而不会改变原始NonFluent API中的任何内容。

1

我想了一会儿,我能够为继承方法提供一些舒适的语法,其中流畅的方法将从f_开始。

下面是一些宏观法宝:

#define FIFTHS(_1, _2, _3, _4, _5, NAME, ...) NAME 
#define MODIFY_ARGS_1(_1_) _1_ _1 
#define MODIFY_ARGS_2(_1_, _2_) _1_ _1, _2_ _2 
#define MODIFY_ARGS_3(_1_, _2_, _3_) _1_ _1, _2_ _2, _3_ _3 
#define MODIFY_ARGS_4(_1_, _2_, _3_, _4_) _1_ _1, _2_ _2, _3_ _3, _4_ _4 
#define MODIFY_ARGS_5(_1_, _2_, _3_, _4_, _5_) _1_ _1, _2_ _2, _3_ _3, _4_ _4, _5_ _5 
#define MODIFY_ARGS(...) FIFTHS(__VA_ARGS__, MODIFY_ARGS_5, MODIFY_ARGS_4, MODIFY_ARGS_3, MODIFY_ARGS_2, MODIFY_ARGS_1)(__VA_ARGS__) 

#define SEQUENCE_1(_1_) _1 
#define SEQUENCE_2(_1_, _2_) _1, _2 
#define SEQUENCE_3(_1_, _2_, _3_) _1, _2, _3 
#define SEQUENCE_4(_1_, _2_, _3_, _4_) _1, _2, _3, _4 
#define SEQUENCE_5(_1_, _2_, _3_, _4_, _5_) _1, _2, _3, _4, _5 
#define SEQUENCE(...) FIFTHS(__VA_ARGS__, SEQUENCE_5, SEQUENCE_4, SEQUENCE_3, SEQUENCE_2, SEQUENCE_1)(__VA_ARGS__) 

#define FLUENTIZE_DERIVE() CONCATENATE(Fluent,CURRENT_BASE) : public CURRENT_BASE 
#define FLUENTIZE_METHOD(name, ...) CONCATENATE(Fluent,CURRENT_BASE)& f_ ## name (MODIFY_ARGS(__VA_ARGS__)) {name(SEQUENCE(__VA_ARGS__)); return *this;} 
#define FLUENTIZE_PROCEDURE(name) CONCATENATE(Fluent,CURRENT_BASE)& f_ ## name() {name(); return *this;} 
#define FLUENTIZE_DFLT_CONSTRUCTOR(name) CONCATENATE(Fluent,CURRENT_BASE)() {} 
#define FLUENTIZE_CONSTRUCTOR(...) CONCATENATE(Fluent,CURRENT_BASE)(MODIFY_ARGS(__VA_ARGS__)) : CURRENT_BASE(SEQUENCE(__VA_ARGS__)) {} 

注:_x_代表类型,_x代表参数名称。现在

,我们有不流畅类:

class Simple { 
    int i=0; 
public: 
    Simple() : Simple(0) {} 
    Simple(int i) {this->i = i;} 
    void setValue(int i) {this->i = i;} 
    void multiplyValue(int i) {this->i *= i;} 
    void halve() {this->i /= 2;} 
    int getValue() {return this->i;} 

}; 

这就是如何重现流畅类:

#define CURRENT_BASE Simple 
class FLUENTIZE_DERIVE() { 
public: 
    FLUENTIZE_DFLT_CONSTRUCTOR() 
    FLUENTIZE_CONSTRUCTOR(int) 
    FLUENTIZE_METHOD(setValue, int) 
    FLUENTIZE_METHOD(multiplyValue, int) 
    FLUENTIZE_PROCEDURE(halve) 
}; 
#undef CURRENT_BASE 

这样,我们创建了一个名为FluentSimple类,用流利的方法f_setValuef_multiplyValuef_halve。用一些宏魔法我自动命名函数参数(参数被命名为序列_1, _2, _3 ...,最高_5进行测试)。请注意,我必须为不使用任何参数的方法创建另一个宏,因为我使用的宏技术无法处理空的宏__VA_ARGS__

现在,这就是如何使用流畅类:

std::cout << 
FluentSimple() 
    .f_setValue(10) 
    .f_multiplyValue(10) 
    .f_halve() 
    .getValue() << std::endl; 

也要注意,使用这样的结构,流畅的类可以访问所有的基类的方法和像的Qt插槽和信号的某些功能。

如果它有缺点,但宏的使用,请让我知道:)