Вопрос

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

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

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

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

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";
}
Это было полезно?

Решение

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

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

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

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

//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 лет в проекте, и из-за шаблонного кода (его много) размеры исполняемых файлов в отладочных версиях, как правило, БОЛЬШИЕ (моя запись составляла 35 МБ или около того).Также был небольшой удар по скорости компиляции.Также напомним, что C ++ 0x, вероятно, будет включать какой-то эквивалентный механизм.Заключение:старайтесь не использовать списки типов, если в этом нет необходимости.

Другие советы

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

Как таковые, они могут быть использованы для создания какого-то типа "объединение", но это только одно из возможных применений.

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top