Динамическая компиляция времени компиляции - PullRequest
2 голосов
/ 23 марта 2011

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

Мне известно о некоторых других 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();
}

1 Ответ

1 голос
/ 16 января 2012

Вот более чистое решение без макросов:

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

template <typename T>
struct RefWrapper
{
    T *self;
    RefWrapper () : self (nullptr) {abort ();} // should never be called
    RefWrapper (T &self) : self (&self) {}
};


template <typename T>
struct PrintOnce : virtual RefWrapper<T>
{
    PrintOnce () {}             // workaround gcc 4.6 bug
    void print_once () {cout << *RefWrapper<T>::self << endl;}
};


template <typename T>
struct PrintTwice : virtual RefWrapper<T>
{
    PrintTwice () {}            // workaround gcc 4.6 bug
    void print_twice ()
    {
        cout << *RefWrapper<T>::self << endl;
        cout << *RefWrapper<T>::self << endl;
    }
};


template <typename T, typename... Args>
struct Mixed : Args...
{
    Mixed (T &self) :
        RefWrapper<T> (self),
        Args ()... {}

    Mixed (const Mixed &copy) :
        RefWrapper<T> (*copy.self),
        Args ()... {}
};


template <template <typename U> class Mixin, typename T>
Mixed<T, Mixin<T> > add_mixin (T &original)
{
    return Mixed<T, Mixin<T> > (original);
}


template <template <typename U> class Mixin, typename T,
          typename... OtherMixins>
Mixed<T, OtherMixins..., Mixin<T> >
add_mixin (Mixed<T, OtherMixins...> &original)
{
    return Mixed<T, OtherMixins..., Mixin<T> > (*original.self);
}


int main ()
{
    string foo = "test";

    auto p1 = add_mixin<PrintOnce> (foo);
    p1.print_once ();

    auto p2 = add_mixin<PrintTwice> (p1);
    p2.print_once ();
    p2.print_twice ();
}

К сожалению, оно по-прежнему не выполняет ваше требование о том, чтобы каждый класс миксина знал обо всех других классах миксина.Хотя я не уверен, возможно ли это даже во время компиляции.

...