C ++ генерирует тело функции, содержащее switch / map из типов аргументов шаблона - PullRequest
1 голос
/ 01 марта 2012

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

Мой компилятор не поддерживает переменные шаблоны, поэтому препроцессор (boost) в настоящее время используется для генерации существующего класса:

template <typename item0, typename item1, typename item2 ..., typename itemN>
struct myclass { /*various operations*/ };

Требуется новая функция func , которая будет запрашивать переменные во время выполнения и возвращать объект, являющийся одним из аргументов шаблона.

Пример:

template <typename item0, typename item1, typename item2 ...>
struct my_class { 

    //...various operations

    //automatic generatation possible?
    std::string * func()
    {
        string s;
        while(data) {

        switch (data[0])
        {
            case item0::id:
                s += item0::get_name();
            case item1::id:
                s += item1::get_name();
            //... for each template arguemnt typename where typename is no void
        }
        }
        return s;
    }
 };

typedef my_class<a, b, c> class_one;
typedef my_class<d, e, f> class_two;
typedef my_class<a, b, c, x, y, z>  class_three;

 int main()
 {
    ...
    class_one test;
    test.func();
    ...
 }

Я бы хотел сгенерировать содержимое функции func (), потому что число элементов будет многочисленным, а количество типов «myclass» будет еще выше.

Может ли кто-нибудь дать мне представление о том, как какие-либо методы, которые могли бы достичь этого?

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

Ответы [ 2 ]

4 голосов
/ 01 марта 2012

Я уже писал такой код, поэтому могу сказать, что это возможно.(Это было для коммерческой работы с закрытым исходным кодом, поэтому я боюсь, что не смогу показать вам код).Вы можете найти действительно хороший пример того, как это сделать, в библиотеке Boost.Variant, в частности http://svn.boost.org/svn/boost/trunk/boost/variant/detail/visitation_impl.hpp.Код очень плотный и продвинутый для C ++, поэтому для его полного понимания может потребоваться день или два.

Краткое резюме: шаблон класса boost::variant работает как объединение с int, хранящим, какой членСоюз действителен.Функция «посещения» позволяет вам предоставить объекту функции перегруженный operator(), который может принимать любого из возможных членов объединения, и он генерирует оператор switch, который обращается к соответствующему члену и вызывает правильную перегрузку operator() для него.,Если вы уже находите это сложным для подражания, или вы еще не знаете о Boost.MPL, я предлагаю вам прекратить читать здесь, прочитать документацию Boost.Variant, а затем переписать свой класс, чтобы иметь возможность использовать это: умныйребята из Boost уже сделали всю работу за вас.Он только для заголовков, поэтому, если вы уже используете Boost, для вас нет новой зависимости.

Этот файл отвечает за генерацию оператора switch.Короче говоря, у него есть две альтернативные реализации.В первом (строки 72-90) используется рекурсивный шаблон visitation_impl_step, который работает как функция факториала, которую вы могли видеть в качестве примера метапрограммирования шаблона.Неспециализированный шаблон рекурсивно вызывает следующий в списке (typename mpl::next<Iter>::type).Результирующий код после развертывания всех шаблонов выглядит как серия функций function0, function1, & c.например:

result_type functionN(variant vnt, visitor vr) {
    if (v.which == N)
        return vr(static_cast<Nth type>(vnt.value));
    else
        functionN-1(vnt, vr);
}

Вторая реализация (строки 193-285) использует магическую библиотеку препроцессора Boost.PP для генерации оператора switch точно так же, как вы хотите, с таким количеством случаев, как boost::variantможет иметьТело каждого случая - это вызов функции шаблона (строки 120-185), которая генерирует вызов для посетителя N-го типа.Большая сложность в этой реализации возникает из-за необходимости беспокоиться о резервном копировании значения внутри variant, чтобы сохранить гарантию сильных исключений, если посетитель или любой задействованный конструктор сгенерирует.

Даже если вы решитесделайте это по-другому, я рекомендую прочитать и понять исходный код Boost.Variant, как учебное упражнение.Это переопределит ваши идеи о том, что возможно (и что разумно) в C ++!

0 голосов
/ 01 марта 2012

Компилятор сможет генерировать код, используя точное определение шаблона.Невозможно заставить компилятор генерировать дополнительные случаи в выражении switch или дополнительные итерации циклов в зависимости от параметров шаблона.

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

...