当前位置:  开发笔记 > 编程语言 > 正文

模板元编程 - 我仍然没有得到它:(

如何解决《模板元编程-我仍然没有得到它:(》经验,为你挑选了5个好方法。

我有一个问题......我不懂模板元编程.

问题是:我读了很多.但这对我来说没有多大意义:/

事实nr.1:模板元编程更快

template 
struct Factorial 
{
    enum { value = N * Factorial::value };
};

template <>
struct Factorial<0> 
{
    enum { value = 1 };
};

// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
    int x = Factorial<4>::value; // == 24
    int y = Factorial<0>::value; // == 1
}

所以这个Metaprogram更快......因为Constant Literal.

但是:在现实世界中我们有不变的文字吗?

我用的大多数程序都会对用户输入作出反

事实nr.2:模板元编程可以实现更好的可维护性.

是啊.析因示例可以维护......但是当涉及到复杂的函数时,我和大多数其他C++程序员都无法读取函数.

调试选项很差(或者至少我不知道如何调试).

模板元编程在哪里有意义?



1> Daniel Earwi..:

正如因子不是非函数语言中递归的现实例子,它也不是模板元编程的现实例子.这只是人们想要向您展示递归的标准示例.

在为实际目的编写模板时,例如在日常库中,模板通常必须根据实例化的类型参数来调整它所做的事情.这可能变得非常复杂,因为模板有条件地有效地选择要生成的代码.这就是模板元编程的原因; 如果模板必须循环(通过递归)并在备选之间进行选择,它实际上就像在编译期间执行以生成正确代码的小程序.

这是一个来自boost文档页面的非常好的教程(实际上摘自一本精彩的书,非常值得一读).

http://www.boost.org/doc/libs/1_39_0/libs/mpl/doc/tutorial/representing-dimensions.html


好答案.+1 - 我希望人们就更好的标准例子达成一致.通常,使用元编程来计算值是没有意义的.作为一种学习练习,它在试图找出TMP时具有启发性,但不是作为一个用例,而不是一个卖点来说服人们这个功能有多棒.

2> LiraNuna..:

我使用模板mete-programming为SSE调配操作符在编译期间优化shuffle.

SSE swizzles('shuffles')只能被屏蔽为字节文字(立即值),因此我们创建了一个'mask merger'模板类,它在编译时合并掩码,以便在发生多次shuffle时:

template 
struct _mask_merger
{
    enum
    {
        ROW0 = ((target >> (((mask >> 0) & 3) << 1)) & 3) << 0,
        ROW1 = ((target >> (((mask >> 2) & 3) << 1)) & 3) << 2,
        ROW2 = ((target >> (((mask >> 4) & 3) << 1)) & 3) << 4,
        ROW3 = ((target >> (((mask >> 6) & 3) << 1)) & 3) << 6,

        MASK = ROW0 | ROW1 | ROW2 | ROW3,
    };
};

这可以工作并产生非凡的代码,而不会产生代码开销和额外的编译时间.



3> jalf..:

所以这个Metaprogram更快......因为Constant Literal.但是:在现实世界中我们有不变的文字吗?我使用的大多数程序都会对用户输入作出反应

这就是为什么它几乎没有用于价值观.通常,它用于类型.使用类型来计算和生成新类型.

有许多现实世界的用途,即使你没有意识到,其中一些你已经熟悉了.

我最喜欢的一个例子是迭代器.它们主要是用通用编程设计的,是的,但模板元编程特别适用于某个地方:

修补指针,以便它们可以用作迭代器.迭代器必须暴露一些typedef,例如value_type.指针不这样做.

所以代码如下(基本上与你在Boost.Iterator中找到的相同)

template 
struct value_type {
  typedef typename T::value_type type;
};

template 
struct value_type {
  typedef T type;
};

是一个非常简单的模板元程序,但它非常有用.它允许您获取任何迭代器类型T的值类型,无论它是指针还是类,只需通过value_type::type.

我认为上述在可维护性方面有一些非常明显的好处.只在迭代器上运行的算法必须实现一次.如果没有这个技巧,你必须为指针做一个实现,而另一个用于"适当的"基于类的迭代器.

类似的技巧boost::enable_if也非常有价值.您有一个函数的重载,应该只为特定的类型集启用.您可以使用元编程来指定条件并将其传递给每个类型,而不是为每种类型定义重载enable_if.

Earwicker已经提到了另一个很好的例子,一个表达物理单位和维度的框架.它允许您表达附加物理单位的计算,并强制执行结果类型.乘以米为单位可以产生数平方米.模板元编程可用于自动生成正确的类型.

但大多数情况下,模板元编程在小的,孤立的情况下使用(并且有用),基本上是为了平滑凸起和异常情况,使一组类型看起来和行为均匀,允许您更有效地使用通用编程



4> Meredith L. ..:

支持Alexandrescu的Modern C++ Design的建议.

当你正在编写一个可以在"选择Foo,Bar和Baz"方法中组合组合的库时,模板真的很闪耀,并且您希望用户以某种形式使用这些片段编译时间.例如,我合着了一个数据挖掘库,它使用模板元编程让程序员决定DecisionType使用什么(分类,排序或回归),InputType期望什么(浮点数,整数,枚举值,等等),以及KernelMethod使用什么(它是一个数据挖掘的事情).然后,我们为每个类别实现了几个不同的类,以便有几十种可能的组合.

实现60个单独的类来执行此操作将涉及许多烦人的,难以维护的代码重复.模板元编程意味着我们可以将每个概念作为代码单元实现,并为程序员提供一个简单的接口,用于在编译时实例化这些概念的组合.

维度分析也是一个很好的例子,但其他人已经涵盖了这一点.

我曾经写过一些简单的编译时伪随机数生成器,只是为了弄乱人们的脑袋,但这并不能算上IMO.


弄乱人们的头脑是可以编程的最好的用途之一!不要低估它的价值.:p

5> sbi..:

阶乘的例子对于真实世界的TMP来说就像"Hello,world!"一样有用.用于通用编程:它是为了向您展示一些有用的技术(递归而不是迭代,"else-if-then"等),这是一个非常简单,相对容易理解的示例,与您的每一个都没有多大关系 - 编码.(你最后一次需要编写一个发出"Hello,world"的程序是什么时候?)

TMP是关于在编译时执行算法的,这意味着一些明显的优势:

由于这些算法失败意味着您的代码无法编译,失败的算法永远不会让您的客户,因此不会失败的客户.对我来说,在过去十年中,这是最重要的一个优势,这使我将TMP引入我所工作的公司的代码中.

由于执行模板元程序的结果是由编译器编译的普通代码,因此代码生成算法的所有优点(减少冗余等)都适用.

当然,由于它们是在编译时执行的,因此这些算法不需要任何运行时间,因此运行速度更快.TMP主要是关于编译时计算,其中包含一些(主要是小型的)内联函数,因此编译器有很多机会来优化生成的代码.

当然,也有缺点:

错误消息可能很糟糕.

没有调试.

代码通常很难阅读.

与往常一样,在每种情况下,您都必须权衡利弊.

至于一个更有用的示例:一旦掌握了类型列表和基于它们的基本编译时算法,您可能会理解以下内容:

typedef 
    type_list_generator< signed char
                       , signed short
                       , signed int
                       , signed long
                       >::result_type
    signed_int_type_list;

typedef 
    type_list_find_if< signed_int_type_list
                     , exact_size_predicate<8>
                     >::result_type
    int8_t;

typedef 
    type_list_find_if< signed_int_type_list
                     , exact_size_predicate<16>
                     >::result_type
    int16_t;

typedef 
    type_list_find_if< signed_int_type_list
                     , exact_size_predicate<32>
                     >::result_type
    int32_t;

这是(几乎简化)我几周前写的实际代码.它将从类型列表中选择适当的类型,替换#ifdef便携式代码中常见的orgies.它不需要维护,无需适应您的代码可能需要移植到的每个平台,如果当前平台没有正确的类型,则会发出编译错误.

另一个例子是:

template< typename TFunc, typename TFwdIter >
typename func_traits::result_t callFunc(TFunc f, TFwdIter begin, TFwdIter end);

给定一个函数f和一个字符串序列,这将剖析函数的签名,将序列中的字符串转换为正确的类型,并使用这些对象调用函数.它主要是TMP内部.

推荐阅读
php
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有