Как использовать списки типов

Я читал о списках в "Современном дизайне С++", и я понял это как своего рода объединение для типов. Помещая различные, не связанные типы в списке типов, можно использовать его для представления более одного типа сразу, без наследования. Я тестировал typelist в некоторых простых функциях с примитивными типами, но я не мог заставить их работать.

Может ли кто-нибудь сказать мне, верно ли мое несоответствие списков типов и дать простой пример реального мира, как использовать списки типов в среднем дневном коде? Спасибо заранее.

Btw, я использую Windows и Visual Studio 2005 и его компилятор.

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

void SomeOperation(DocumentItem* p)
{
    if (TextArea* pTextArea = dynamic_cast<TextArea*>(p))
    {
        ... operate on a TextArea object ...
    }
    else if (VectorGraphics* pVectorGraphics =
        dynamic_cast<VectorGraphics*>(p))
    {
        ... operate on a VectorGraphics object ...
    }
    else if (Bitmap* pBitmap = dynamic_cast<Bitmap*>(p))
    {
        ... operate on a Bitmap object ...
    }
    else
    {
        throw "Unknown type passed";
    }
}

Это работает, но я не вижу преимущества над наследованием, которое способно сделать то же самое. А динамические ролики не работают на примитивных типах. Можно ли использовать его как возвращаемое значение, например:

typedef Typelist<int, string> mylist
mylist myfunction() {
    if(foo == bar)
        return 5;

    return "five";
}

Ответ 1

Список типов - это обобщенные коллекции времени коллекций типов. Если вы используете dynamic_cast, вам не хватает точки, потому что это не нужно, потому что это статическая концепция времени компиляции.

Это работает, но я не вижу преимущества над наследованием, которое способно сделать то же самое.

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

Списки типов можно использовать для создания объекта для передачи набора аргументов функции. Это фрагмент кода, который вызывает обобщенные функторы из 5 параметров (другое понятие из Modern С++ design) с аргументами, предоставленными в tupe (еще один) с списком типов, который определяет типы объектов, хранящихся в кортеже:

//functor is just a holder of a pointer to method and a pointer to object to call this 
//method on; (in case you are unfamiliar with a concept)
template<class R, class t0, class t1, class t2, class t3, class t4>
R call(Loki::Functor<R,LOKI_TYPELIST_5(t0, t1, t2, t3, t4
    )> func,
    Loki::Tuple<LOKI_TYPELIST_5(t0, t1, t2, t3, t4)> tuple)
{
    ///note how you access fields
    return func(Loki::Field<0>(tuple), Loki::Field<1>(tuple),
        Loki::Field<2>(tuple), Loki::Field<3>(tuple),
        Loki::Field<4>(tuple));
}

//this uses the example code
#include<iostream>
using namespace std;

int foo(ostream* c,int h,float z, string s,int g)
{
    (*c)<<h<<z<<s<<g<<endl;
    return h+1
}

int main(int argc,char**argv)
{
    Loki::Functor<int,LOKI_TYPELIST_5(ostream*, int, float, string, int)> f=foo;
    //(...)
    //pass functor f around
    //(...)
    //create a set of arguments
    Loki::Tuple<LOKI_TYPELIST_5(ostream*, int, float, string, int)> tu;
    Field<0>(tu)=&cout;
    Field<1>(tu)=5;
    Field<2>(tu)=0.9;
    Field<3>(tu)=string("blahblah");
    Field<4>(tu)=77;
    //(...)
    //pass tuple tu around, possibly save it in a data structure or make many 
    //specialized copies of it, or just create a memento of a call, such that 
    //you can make "undo" in your application; note that without the typelist 
    //you would need to create a struct type to store any set of arguments;
    //(...)
    //call functor f with the tuple tu
    call(f,tu);
}

Обратите внимание, что только с другими понятиями, такими как кортежи или функторы, списки типов становятся полезными. Кроме того, я испытываю Loki около 2 лет в проекте, и из-за кода шаблона (его много) размеры исполняемых файлов в версиях DEBUG, как правило, BIG (мой рекорд был 35 МБ или около того). Кроме того, был немного удар по скорости компиляции. Также напомним, что С++ 0x, вероятно, будет включать в себя некоторый эквивалентный механизм. Вывод: старайтесь не использовать списки типов, если вам это не нужно.

Ответ 3

Typelists - это способ передачи "списков параметров" в метафайлы шаблонов, которые "выполняются" как часть процесса компиляции.

Таким образом, они могут использоваться для создания своего рода типа объединения, но это только одно возможное использование.

Для примера "реальный мир": мы использовали списки типов как способ генерации метода "QueryInterface" автоматически при реализации COM-объектов в Comet.

Это позволило вам написать такой код:

class Dog : public implement_qi<make_list<IAnimal, INoisy, IPersistStream> >
{
    // The implement_qi template has provided
    // an implementation of COM QueryInterface method for us without
    // having to write an ugly ATL "message map" or use any Macros.
    ...
}

В этом примере "make_list" был шаблоном, используемым для генерации "списка типов", который шаблон реализации_qi мог затем "перечислить" на сгенерировать соответствующий код QueryInterface.