Я пытаюсь найти способ определения динамических миксинов во время компиляции. В настоящее время у меня есть очень хакерское решение, которое лишь частично делает то, что я хочу, но я не уверен, как его улучшить.
Мне известно о некоторых других C ++ подобных решениях, использующих список типов, но они требуют статического определения всех типов, которых я стараюсь избегать.
Это в основном всего лишь упражнение на мысль, чтобы лучше изучить C ++, и я уверен, что моя текущая реализация не очень хорошая C ++. Любые предложения по улучшению или другие идеи, которые можно попробовать, будут приветствоваться.
Основные проблемы с моей текущей реализацией:
- Каждый класс mixin осознает только себя и классы ниже, чем он сам в иерархии. Мне бы хотелось, чтобы каждый класс mixin мог возвращать новый mixin с другим базовым типом. В приведенном ниже примере кода я бы хотел, чтобы
PrintOnce
мог иметь метод, который возвращает объект PrintTwice<PrintOnce<Printer<int > > >
.
- Любое использование этой идеи должно иметь порядок включения заголовка. Весь код котельной плиты в начале должен быть в одном заголовке, затем должны быть определены все классы mixin, и, наконец, можно определить функцию
make_mixed
. В настоящее время любой миксин, определенный после функции make_mixed
, игнорируется.
- Макрос и общая хакерская реализация.
Я прошу прощения за длину, но это самый упрощенный пример, который я мог придумать.
Спасибо за любую помощь.
#include <string>
#include <vector>
#include <iostream>
using namespace std;
template<class Underlying>
struct Printer
{
Printer(const Underlying &val) : val_(val) {}
Underlying get_val() { return val_; }
private:
Underlying val_;
};
#define CURRENT_NUMBER_MIXED_IN_CLASSES() \
MixinCount<0, __LINE__>::value
#define INCREMENT_MIXIN_CLASS_COUNTER() \
template<int id> \
struct MixinClassCounter< CURRENT_NUMBER_MIXED_IN_CLASSES(), id> \
{ \
static const bool is_defined = true; \
}
template< bool b, typename i, typename j >
struct select_value;
template<class i, class j>
struct select_value<true, i, j>
{
static const int value = i::value;
};
template<class i, class j>
struct select_value<false, i, j>
{
static const int value = j::value;
};
template<int i>
struct IntToVal
{
static const int value = i;
};
namespace
{
template<int count, int id>
struct MixinClassCounter
{
static const bool is_defined = false;
};
template<int count, int id>
struct MixinCount
{
static const int value = select_value<MixinClassCounter<count, id>::is_defined,
MixinCount<count + 1, id>,
IntToVal<count> >::value;
};
template<class Underlying, int i>
struct MixinBuilder {};
template<class Underlying>
struct MixinBuilder<Underlying, 0>
{
typedef Printer<Underlying> type;
};
INCREMENT_MIXIN_CLASS_COUNTER();
}
#define DECLARE_MIXIN_BEGIN(name) \
template<class Base> \
struct name : Base \
{ \
template<class Underlying> \
name(const Underlying &val) : Base(val) {}
#define DECLARE_MIXIN_END(name) \
}; \
namespace \
{ \
template<class Underlying> \
struct MixinBuilder<Underlying, CURRENT_NUMBER_MIXED_IN_CLASSES()> \
{ \
typedef name< typename MixinBuilder<Underlying, CURRENT_NUMBER_MIXED_IN_CLASSES() - 1>::type > type; \
}; \
INCREMENT_MIXIN_CLASS_COUNTER(); \
} \
DECLARE_MIXIN_BEGIN(PrintOnce)
void print_once()
{
cout << Base::get_val() << endl;
}
DECLARE_MIXIN_END(PrintOnce)
DECLARE_MIXIN_BEGIN(PrintTwice)
void print_twice()
{
cout << Base::get_val() << endl;
cout << Base::get_val() << endl;
}
DECLARE_MIXIN_END(PrintTwice)
template<class T>
typename MixinBuilder<T, CURRENT_NUMBER_MIXED_IN_CLASSES() - 1>::type make_mixed(const T &val)
{
return typename MixinBuilder<T, CURRENT_NUMBER_MIXED_IN_CLASSES() - 1>::type(val);
}
int main()
{
string test("this is a test");
auto printable_string = make_mixed(test);
printable_string.print_once();
printable_string.print_twice();
}