Каков хороший способ «переопределения»? не беглый интерфейс как беглый?

То, что я ищу, так это иметь не беглый класс:

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 методы для начала.
Мы могли бы также использовать редактор объектов, о котором я задавал вопрос:
Является ли Object Editor хорошим подходом, если нужно вызвать несколько функций-членов?, но у него много недостатков.

Знаете ли вы какие-нибудь хорошие методы для этого? (не изменяя не-беглый класс напрямую?)

1

Решение

Лучший подход, который вы могли бы использовать с 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.

2

Другие решения

Некоторое время я думал об этом и смог создать удобный синтаксис для подхода наследования, где беглые методы начнутся с 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_setValue,f_multiplyValue а также f_halve, С некоторой макро-магией я автоматически назвал аргументы функции (аргументы названы как последовательность _1, _2, _3 ..., вплоть до _5 для тестирования). Обратите внимание, что мне пришлось сделать еще один макрос для методов, которые не принимают никаких аргументов, потому что метод макросов, который я использовал, не может иметь дело с пустым __VA_ARGS__ макро.

Теперь, как использовать свободный класс:

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

Также обратите внимание, что в этой конструкции свободный класс имеет доступ ко всем методам базового класса и некоторым функциям, таким как слоты и сигналы Qt.

Если у него есть какие-либо недостатки, кроме использования макросов, пожалуйста, дайте мне знать 🙂

1

В качестве другого ответа я выбрал другой подход, который приводит к минимальному добавлению кода:

Редактор:

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));

Это лучшее, что я мог сделать 🙂

0
По вопросам рекламы [email protected]