Лучший способ использовать C++ под названием идиома параметра?

Здесь - ответ о том, как передавать специальные символы в скрипты Python.

Я напечатал значение args и получил следующий вывод:

args = ap.parse_args()
print(args)
Out: 
Namespace(dm='\\t', tab='my_tab')

, поэтому args.dm - это не строка \t, а '\\t'. Вы можете передать \t как объяснено в ответе, упомянутом выше:

python $scripts/split_tab.py --tab my_tab --dm

, поэтому argparser хранит значение \t, вы можете проверить его через

print(args.dm == '\t')
Out:
True

[ 1118] Или вы можете сравнить args.dm со строкой '\\t' и заменить ее символом \t.

\t'

, поэтому argparser хранит значение \t, вы можете проверить его через

[111] [ 1118] Или вы можете сравнить args.dm со строкой '\\t' и заменить ее символом \t.

9
задан manlio 13 March 2014 в 15:37
поделиться

6 ответов

Возможно, не, для чего Вы хотите услышать, но я, каждый думает, что нормально иметь много ужасных преобразований типа и шаблонных параметров в коде библиотеки, это (более или менее) скрыто от клиента, пока это безопасно и делает жизнь клиента намного легче. Красота в коде библиотеки не находится в самом коде, а в коде он позволяет клиентам записать. Возьмите STL, например.

Я также разработал небольшую библиотеку GUI как персональный проект с в основном теми же стремлениями, как Вы и часть кода становитесь довольно уродливыми в нем, но в конце это позволяет мне писать красивый клиентский код (по крайней мере, в моем (возможно извращенный) глаза), и это что количества, по моему скромному мнению.

9
ответ дан 4 December 2019 в 12:22
поделиться

Как насчет...?

template <class T>
class _sharedWindowOpts: public detail::_baseCreateWindowOpts {

protected: // (protected so the inheriting classes may also use it)

    T & me() { return static_cast<T&>(*this); }               // !

public:
    // No required parameters in this case.
    _sharedWindowOpts() { };

    typedef T optType;

    // Commonly used options
    optType& at(int x, int y) { mX=x; mY=y; return me(); };   // !
    // ...
};
5
ответ дан 4 December 2019 в 12:22
поделиться

Вы могли просто объединить вызовы метода в цепочку обратным порядком наследования?

Таким образом в Вашем примере Вы сделали бы что-то как

Окно Window = CreateWindow ("нечто") .menu (hmenu) .owner (hwnd) .at (0,0) .background (hbr);

Я понимаю, что это не на 100% прозрачно, но кажется немного легче, и почти исправьте.

2
ответ дан 4 December 2019 в 12:22
поделиться

Шаблоны являются горячими.

Но POP (Простой Полиморфизм) не мертв.

Почему бы не возвратить (умный) указатель на подкласс?

0
ответ дан 4 December 2019 в 12:22
поделиться

Я не знаю, люблю ли я этот ответ, но здесь являюсь возможностью с помощью вычета аргумента шаблона. ОБРАТИТЕ ВНИМАНИЕ, что у меня нет своего компилятора на мне, я перепроверю его завтра, если кто-то еще там не захочет дать ему водоворот.

class sharedWindowOpts
{
public:

  sharedWindowOpts() {};

  // Commonly used options
  template <class optType>
  static optType& at(int x, int y, optType& opts) { opts.mX=x; opts.mY=y; return opts; };

  template <class optType>
  static optType& background(HBRUSH b, optType& opts) { opts.mBackground=b; return opts; };

  // etc...
}

class createWindowOpts : public sharedWindowOpts
{
public:
  createWindowOpts() : sharedwindowOpts() {};

  // These can't be used with child windows, or aren't needed
  template <class optType>
  static optType& menu(HMENU m, optType& opts) { opts.mMenuOrId=m; return opts; };

  template <class optType>
  static optType& owner(HWND hwnd, optType& opts) { opts.mParentOrOwner=hwnd; return opts; };
 }

Затем Вы назвали бы CreateWindow как это:

CreateWindow( createWindowOpts::owner(hwnd,
              createWindowOpts::at(0, 100,     // can use createWindowOpts because it doesn't hide sharedWindowsOpts::at
              createWindowOpts::menu(hmenu, createWindowOpts() ) ) ) );

Неприятные вещи об этом, конечно, должны использовать синтаксис вызова статического метода и все дополнительные круглые скобки. При замене статических функций членства не являющимися членом функциями, это может быть устранено. Это действительно избегает преобразования типа и дополнительных шаблонных классов, все же.

Лично, у меня был бы нечетный код в библиотеке как с Вашим методом, чем везде как библиотека пользуются в моем.

1
ответ дан 4 December 2019 в 12:22
поделиться

Я знаю, что опаздываю на год и не хватает доллара, но все равно предложу свое решение.

//////// Base.. 

template<typename DerivedBuilder, typename Options>
class Builder
{
protected:
    Builder() {}
    DerivedBuilder& me() { return *static_cast<DerivedBuilder*>(this); }

    Options options;
};


//////////////////////////       A       //////////////////////////


class Options_A
{
public:
    Options_A() : a(7) {}
    int a;
};

class Builder_A;

class A 
{
public:
    virtual ~A() {}
    virtual void print() { cout << "Class A, a:" << a << endl; }

protected:
    friend class Builder_A;
    A(const Options_A& options) : a(options.a) {}
    int a;
};



template<typename DerivedBuilder, typename Options = Options_A>
class BuilderT_A : public Builder<DerivedBuilder, Options>
{
public:
    using Builder<DerivedBuilder, Options>::options;
    using Builder<DerivedBuilder, Options>::me;
    DerivedBuilder& a(int p) { options.a = p; return me(); }
};


class Builder_A : public BuilderT_A<Builder_A>
{
public:
    shared_ptr<A> create()
    {
        shared_ptr<A> obj(new A(options));
        return obj;
    }
};

//////////////////////////      B       //////////////////////////



class Options_B : public Options_A
{
public:
    Options_B() : b(8) {}
    int b;
};

class Builder_B;

class B : public A 
{
public:
    virtual ~B() {}
    virtual void print() { cout << "Class B, a:" << a << ", b:" << b << endl; }

protected:
    friend class Builder_B;
    B(const Options_B& options) : A(options), b(options.b) {}
    int b;
};


template<typename DerivedBuilder, typename Options = Options_B>
class BuilderT_B : public BuilderT_A<DerivedBuilder, Options>
{
public:
    using Builder<DerivedBuilder, Options>::options;
    using Builder<DerivedBuilder, Options>::me;
    DerivedBuilder& b(int p) { options.b = p; return me(); }
};


class Builder_B : public BuilderT_B<Builder_B>
{
public:
    shared_ptr<B> create()
    {
        shared_ptr<B> obj(new B(options));
        return obj;
    }
};



//////////////////////////       C       //////////////////////////



class Options_C : public Options_B
{
public:
    Options_C() : c(9) {}
    int c;
};

class Builder_C;

class C : public B 
{
public:
    virtual ~C() {}
    virtual void print() { cout << "Class C, a:" << a << ", b:" << b << ", c:" << c << endl; }

protected:
    friend class Builder_C;
    C(const Options_C& options) : B(options), c(options.c) {}
    int c;
};


template<typename DerivedBuilder, typename Options = Options_C>
class BuilderT_C : public BuilderT_B<DerivedBuilder, Options_C>
{
public:
    using Builder<DerivedBuilder, Options>::options;
    using Builder<DerivedBuilder, Options>::me;
    DerivedBuilder& c(int p) { options.c = p; return *static_cast<DerivedBuilder*>(this); }
};


class Builder_C : public BuilderT_C<Builder_C>
{
public:
    shared_ptr<C> create()
    {
        shared_ptr<C> obj(new C(options));
        return obj;
    }
};





///////////////////////////////////////////////////////////////////////////


int main()
{
    shared_ptr<A> a = Builder_A().a(55).a(1).create();
    a->print();

    shared_ptr<B> b = Builder_B().b(99).b(2).a(88).b(4).a(2).b(3).create();
    b->print();

    shared_ptr<C> c = Builder_C().a(99).b(98).c(97).a(96).c(6).b(5).a(4).create();
    c->print();

    return 0;
}

/* Output:

Class A, a:1
Class B, a:2, b:3
Class C, a:4, b:5, c:6

*/

C происходит от B, а B является производным от A. Я повторил параметры, чтобы показать, что их можно расположить в любом желаемом порядке.

0
ответ дан 4 December 2019 в 12:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: