Здесь - ответ о том, как передавать специальные символы в скрипты 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
.
Возможно, не, для чего Вы хотите услышать, но я, каждый думает, что нормально иметь много ужасных преобразований типа и шаблонных параметров в коде библиотеки, это (более или менее) скрыто от клиента, пока это безопасно и делает жизнь клиента намного легче. Красота в коде библиотеки не находится в самом коде, а в коде он позволяет клиентам записать. Возьмите STL, например.
Я также разработал небольшую библиотеку GUI как персональный проект с в основном теми же стремлениями, как Вы и часть кода становитесь довольно уродливыми в нем, но в конце это позволяет мне писать красивый клиентский код (по крайней мере, в моем (возможно извращенный) глаза), и это что количества, по моему скромному мнению.
Как насчет...?
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(); }; // !
// ...
};
Вы могли просто объединить вызовы метода в цепочку обратным порядком наследования?
Таким образом в Вашем примере Вы сделали бы что-то как
Окно Window = CreateWindow ("нечто") .menu (hmenu) .owner (hwnd) .at (0,0) .background (hbr);
Я понимаю, что это не на 100% прозрачно, но кажется немного легче, и почти исправьте.
Шаблоны являются горячими.
Но POP (Простой Полиморфизм) не мертв.
Почему бы не возвратить (умный) указатель на подкласс?
Я не знаю, люблю ли я этот ответ, но здесь являюсь возможностью с помощью вычета аргумента шаблона. ОБРАТИТЕ ВНИМАНИЕ, что у меня нет своего компилятора на мне, я перепроверю его завтра, если кто-то еще там не захочет дать ему водоворот.
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() ) ) ) );
Неприятные вещи об этом, конечно, должны использовать синтаксис вызова статического метода и все дополнительные круглые скобки. При замене статических функций членства не являющимися членом функциями, это может быть устранено. Это действительно избегает преобразования типа и дополнительных шаблонных классов, все же.
Лично, у меня был бы нечетный код в библиотеке как с Вашим методом, чем везде как библиотека пользуются в моем.
Я знаю, что опаздываю на год и не хватает доллара, но все равно предложу свое решение.
//////// 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. Я повторил параметры, чтобы показать, что их можно расположить в любом желаемом порядке.