如何使用类型列表

发布于 2024-07-21 20:47:01 字数 1076 浏览 11 评论 0 原文

我在《现代 C++ 设计》中读到了有关类型列表的内容,我将其理解为某种类型的联合。 通过将不同的、不相关的类型放入类型列表中,可以使用它一次表示多个类型,而无需继承。 我在一些具有原始类型的简单函数中测试了类型列表,但我无法让它们中的任何一个工作。

有人可以告诉我我对类型列表的理解是否正确,并给出一个简单的现实世界示例如何在日常平均代码中使用类型列表? 提前致谢。

顺便说一句,我正在使用 Windows 和 Visual Studio 2005 及其编译器。

编辑:我的示例消失了,我使用 vs 中的沙箱项目来测试这些东西。 但它很安静,类似于 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";
}

I read about typelists in 'Modern C++ Design' and I understood it as some kind of union for types. By putting diffrent, non-related types in a typelist, one can use it to represent more than one type at once, without inheritance. I tested typelist in some simple functions with primitive types, but I couldn't get any of them to work.

Could someone tell me if my unterstanding of typelists is right and give an simple real world example how to use typelists in every day average code? Thanks in advance.

Btw, I'm using Windows and Visual Studio 2005 and its compiler.

EDIT: my examples are gone, I use a sandbox project in vs to test those things. But it was quiet similar to code in Dobbs tutorial:

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";
    }
}

This works but I don't see the advantage over inheritance which is capable to do the same. And dynamic cast don't work on primitive types. Is it possible to use it as a return value like:

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

    return "five";
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

千笙结 2024-07-28 20:47:01

类型列表是通用的编译时类型集合。 如果您使用dynamic_cast,那么您就错过了重点,因为不需要它,因为它是静态的编译时概念。

这可行,但我没有看到比能够做同样事情的继承有什么优势。

您不能使任何现有类型继承您想要的任何类型。 这根本不可行,因为这个现有类型可能是内置类型或来自库的类型。
将类型列表视为任何合理数量的类型(而不仅仅是 2 个)的类型列表(例如在 std::pair 中)的扩展。

类型列表可用于创建将一组参数传递给函数的工具。 这是一段代码,它调用 5 个参数的广义函子(现代 C++ 设计的另一个概念),参数在一个元组(又一个)中提供,类型列表定义元组中保存的对象的类型:

//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 版本中的可执行文件的大小往往很大(我的记录是 35 MB 左右)。 编译速度也受到了一些影响。 另请记住,C++0x 可能会包含一些等效的机制。 结论:如果没有必要,尽量不要使用类型列表。

The typelists are generic compile-time collections of types. If you use dynamic_cast, you are missing the point, because it should not be needed, because it is a static, compile time concept.

This works but I don't see the advantage over inheritance which is capable to do the same.

You cannot make any existing type inherit from anything you want. This is simply not feasible, because this existing type may be a built in type or a type from a library.
Think of the typelists as extensions of lists of types (e.g. in std::pair) for any reasonable number of types (instead of just 2).

The typelists can be used to create a facility to pass around a set of arguments to a function. This is a piece of code that calls generalized functors of 5 parameters (another concept from Modern C++ design) with the arguments supplied in a tupe (yet another one) with the typelist that defines types of objects held in the 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);
}

Note that only with other concepts like tuples or functors the typelists start to be useful.
Also, I have been experiencing Loki for about 2 years in a project and because of the template code (a lot of it) the sizes of executables in DEBUG versions tend to be BIG (my record was 35 MB or so). Also there was a bit of hit on the speed of compilation. Also recall that C++0x is probably going to include some equivalent mechanism. Conclusion: try not to use typelists if you don't have to.

时光与爱终年不遇 2024-07-28 20:47:01

类型列表是一种将“参数列表”传递给模板元程序的方法,模板元程序作为编译过程的一部分“执行”。

因此,它们可用于生成某种“联合”类型,但这只是一种可能的用途。

对于“真实世界”的示例:在 Comet 库。

它允许您编写如下代码:

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 模板可以“枚举”到 生成适当的 QueryInterface 代码

Typelists are a way of passing "lists of parameters" to template meta programs that "execute" as part of the compilation process.

As such, they can be used to generate some sort of "union" type, but this is only one possible use.

For a "real-world" example: We used typelists as a way to generate the "QueryInterface" method automatically when implementing COM objects in the Comet library.

It allowed you to write code like this:

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.
    ...
}

In this example, "make_list" was a template used to generate a "type list", which the implement_qi template could then "enumerate over" to generate the appropriate QueryInterface code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文