Подтвердить что ты не робот

Кто-нибудь использует метапрограммирование шаблонов в реальной жизни?

Я обнаружил шаблон метапрограммирования более 5 лет назад и получил огромный удар по чтению "Современный дизайн С++" , но я никогда не нашел возможности использовать его в реальной жизни.

Вы когда-либо использовали эту технику в реальном коде?

Участники Boost не должны применяться; o)

4b9b3361

Ответ 1

Я когда-то использовал метапрограммирование шаблона в С++ для реализации метода, называемого "символическим возмущением" для обработки вырожденного ввода в геометрических алгоритмах. Представляя арифметические выражения в виде вложенных шаблонов (т.е. В основном путем написания деревьев разбора вручную), я смог передать весь анализ выражений в процессор шаблонов.

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

Конечно, вы могли бы сделать то же самое, реализовав небольшой язык DSL (язык, специфичный для домена) для ваших выражений, и вставку переведенного кода на С++ в вашу обычную программу. Это даст вам все преимущества оптимизации, а также будет более разборчивым, но компромисс заключается в том, что вам нужно поддерживать парсер.

Ответ 2

Я нашел политики, описанные в Modern С++ Design, действительно полезными в двух ситуациях:

  • Когда я разрабатываю компонент, который, как я ожидаю, будет повторно использован, но несколько иначе. Alexandrescu предлагает использовать политику, чтобы отразить дизайн, который здесь очень хорошо подходит - он помогает мне задавать такие вопросы, как "Я мог бы сделать это с помощью фонового потока, но что, если кто-то позже захочет сделать это во временных срезах?" Хорошо, я просто пишу свой класс, чтобы принять ConcurrencyPolicy и реализовать тот, который мне нужен в данный момент. Тогда, по крайней мере, я знаю, что человек, который приходит позади меня, может писать и вставлять новую политику, когда она в ней нуждается, без необходимости полностью переделывать мой дизайн. Предостережение: Иногда я должен править, или это может выйти из-под контроля - вспомните принцип YAGNI

  • Когда я пытаюсь реорганизовать несколько подобных блоков кода в один. Обычно код будет скопирован и изменен немного, потому что в противном случае у него было бы слишком много логики if/else или потому, что типы были слишком разными. Я обнаружил, что политики часто допускают чистую версию для всех вариантов, где традиционная логика или множественное наследование не будут.

Ответ 3

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

Ответ 4

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

Для чтения приложения, Todd Veldhuizen является большим именем в этой области. Популярная книга С++ и объектно-ориентированные числовые вычисления для ученых и инженеров Даоки Янга.

Ответ 5

Мета-программирование шаблонов - замечательный и мощный метод при написании библиотек С++ . Я использовал его несколько раз в пользовательских решениях, но, как правило, менее элегантное старое решение на языке С++ легче получить через обзор кода и упростить поддержку для других пользователей.

Однако при написании многократно используемых компонентов/библиотек у меня много пробега из мета-программирования шаблонов. Я не говорю ни о чем, как о больших элементах Boost, о небольших компонентах, которые будут часто использоваться повторно.

Я использовал TMP для системы singleton, где пользователь мог указать, какой тип синглтона они пожелают. Интерфейс был очень простым. Под ним работал мощный TMP.

template< typename T >
T& singleton();

template< typename T >
T& zombie_singleton();

template< typename T >
T& phoenix_singleton();

Еще одно успешное использование упростило наш уровень IPC. Он построен с использованием классического стиля OO. Каждое сообщение должно основываться на абстрактном базовом классе и переопределять некоторые методы сериализации. Ничего слишком экстремального, но он генерирует много кодовых табличек.

Мы набросили на него TMP и автоматизировали генерацию всего кода для простого случая сообщений, содержащих только данные POD. Сообщения TMP по-прежнему использовали OO-сервер, но они значительно уменьшают количество кодовых табличек. TMP также использовался для генерации ветки сообщений. Со временем все наше сообщение перенесено на метод TMP. Было проще и меньше кода для создания простой структуры POD для передачи сообщений и добавления нескольких (возможно, 3) строк, необходимых для получения TMP для создания классов, чем для получения нового сообщения для отправки обычного класса по IPC рамки.

Ответ 6

Я использую метапрограммирование шаблона все время, но в D, а не С++. С++ template metalanguage изначально был разработан для простой параметризации и почти полностью стал полным метаязыком Тьюринга. Таким образом, тарелка Тьюринга может использовать только Андрея Александреску, а не просто смертных.

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

Ответ 7

Большинство программистов, которые используют метапрограммирование шаблонов, используют это косвенно, через библиотеки, такие как boost. Они даже не знают, что происходит за кулисами, только потому, что упрощает синтаксис некоторых операций.

Ответ 8

Я использовал его совсем немного с кодом DSP, особенно с FFT, циклическими буферами фиксированного размера, преобразованиями Hasamard и т.п.

Ответ 9

Для тех, кто знаком с библиотекой шаблонов Oracle (OTL), boost:: any и Loki (тот, что описан в Modern С++ Design), здесь приведено доказательство концептуального кода TMP, позволяющего хранить одну строку otl_stream в контейнере vector<boost::any> и получить доступ к данным по номеру столбца. И "Да", я собираюсь включить его в производственный код.

#include <iostream>
#include <vector>
#include <string>
#include <Loki/Typelist.h>
#include <Loki/TypeTraits.h>
#include <Loki/TypeManip.h>
#include <boost/any.hpp>
#define OTL_ORA10G_R2
#define OTL_ORA_UTF8
#include <otlv4.h>

using namespace Loki;

/* Auxiliary structs */
template <int T1, int T2>
struct IsIntTemplateEqualsTo{
    static const int value = ( T1 == T2 );
};

template <int T1>
struct ZeroIntTemplateWorkaround{
    static const int value = ( 0 == T1? 1 : T1 );
};


/* Wrapper class for data row */
template <class TList>
class T_DataRow;


template <>
class T_DataRow<NullType>{
protected:
    std::vector<boost::any> _data;
public:
    void Populate( otl_stream& ){};
};


/* Note the inheritance trick that enables to traverse Typelist */
template <class T, class U>
class T_DataRow< Typelist<T, U> >:public T_DataRow<U>{
public:
    void Populate( otl_stream& aInputStream ){
        T value;
        aInputStream >> value;
        boost::any anyValue = value;
        _data.push_back( anyValue );

        T_DataRow<U>::Populate( aInputStream );
    }

    template <int TIdx>
    /* return type */
    Select<
        IsIntTemplateEqualsTo<TIdx, 0>::value,
        typename T,
        typename TL::TypeAt<
            U,
            ZeroIntTemplateWorkaround<TIdx>::value - 1
        >::Result
    >::Result
    /* sig */
    GetValue(){
    /* body */
        return boost::any_cast<
            Select<
                IsIntTemplateEqualsTo<TIdx, 0>::value,
                typename T,
                typename TL::TypeAt<
                    U,
                    ZeroIntTemplateWorkaround<TIdx>::value - 1
                >::Result
            >::Result
        >( _data[ TIdx ] );
    }
};


int main(int argc, char* argv[])
{
    db.rlogon( "AMONRAWMS/[email protected]" ); // connect to Oracle
    std::cout<<"Connected to oracle DB"<<std::endl;
    otl_stream o( 1, "select * from blockstatuslist", db );

    T_DataRow< TYPELIST_3( int, int, std::string )> c;
    c.Populate( o );
    typedef enum{ rcnum, id, name } e_fields; 
    /* After declaring enum you can actually acess columns by name */
    std::cout << c.GetValue<rcnum>() << std::endl;
    std::cout << c.GetValue<id>() << std::endl;
    std::cout << c.GetValue<name>() << std::endl;
    return 0;
};

Для тех, кто не знаком с указанными библиотеками.

Проблема с OTL otl_stream состоит в том, что можно получить доступ к данным столбцов только в последовательном порядке, объявив переменные соответствующего типа и применив объект operator >> to otl_stream следующим образом:

otl_stream o( 1, "select * from blockstatuslist", db );
int rcnum; 
int id;
std::string name;
o >> rcnum >> id >> name; 

Это не всегда удобно. Обходной путь состоит в том, чтобы написать некоторый класс-оболочку и заполнить его данными из otl_stream. Желание иметь возможность объявлять список типов столбцов, а затем:

  • возьмем тип T столбца
  • объявить переменную этого типа
  • применить olt_stream::operator >>(T&)
  • сохранить результат (в векторе boost:: any)
  • возьмите тип следующего столбца и повторите, пока все столбцы не обработаны

Вы можете сделать все это с помощью Loki Typelist struct, специализации шаблона и наследования.

С помощью библиотечных конструкций Loki вы также можете генерировать кучу функций GetValue, которые возвращают значения соответствующего типа, выводя их из номера столбца (фактически количество типов в Typelist).

Ответ 10

Нет. Я не использовал его в производственном коде.

Почему?

  • Мы должны поддерживать 6 + платформы с собственными компиляторами платформы. Это достаточно сложно использовать STL в этой среде, не говоря уже о современном шаблоне методы.
  • Разработчики, похоже, больше не поддерживают продвижение С++. Мы используем С++ когда мы должны. У нас есть устаревший код с устаревшими проектами. Новый код сделанные во что-то еще, например, Java, Javascript, Flash.

Ответ 11

Спустя почти 8 месяцев после этого я наконец использовал TMP, я использую TypeList интерфейсов для реализации QueryInterface в базовый класс.

Ответ 12

Я использую его с boost:: statechart для больших statemachines.

Ответ 13

Да, у меня есть, в основном, некоторые вещи, которые напоминают утиную печать, когда я обертывал устаревший API в более современном интерфейсе на С++.

Ответ 14

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

Например, вы не можете перебирать элементы boost:: tuple < > , потому что вы можете обращаться к ним только во время компиляции. Вы должны использовать метапрограммирование шаблонов для достижения того, что было бы простым и понятным С++, и это всегда происходит, когда пользователи С++ недостаточно осторожны, чтобы не переместить слишком много вещей во время компиляции. Иногда бывает трудно понять, когда определенное использование логики компиляции будет проблематичным, и иногда программисты хотят попробовать и проверить, что они прочитали в Alexandrescu's. Во всяком случае, это очень плохая идея, на мой взгляд.

Ответ 15

Многие программисты часто не используют шаблоны из-за плохой поддержки компилятора до недавнего времени. Однако, хотя в шаблонах было много проблем в pas, более новые компиляторы имеют гораздо лучшую поддержку. Я пишу код, который должен работать с GCC на Mac и Linux, а также с Microsoft Visual С++, и только с GCC 4 и VС++ 2005, что этот компилятор отлично поддержал стандарт.

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

Очевидный пример классов контейнеров, но шаблонов также полезен для многих других вещей. Два примера из моей собственной работы:

  • Умные указатели (например, подсчет ссылок, копирование на запись и т.д.).
  • Математические классы поддержки, такие как матрицы, векторы, сплайны и т.д., которые должны поддерживать различные типы данных и по-прежнему быть эффективными.