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

C++模板是伪装的宏吗?

如何解决《C++模板是伪装的宏吗?》经验,为你挑选了9个好方法。

我已经用C++编程了几年,我已经使用了很多STL并且已经创建了我自己的模板类几次以了解它是如何完成的.

现在我正在尝试将模板更深入地集成到我的OO设计中,一个唠叨的想法不断回到我身边:它们只是一个宏,真的......你可以使用#defines实现(而不是UGLY)auto_ptrs,如果你真的想要.

这种思考模板的方式有助于我理解我的代码将如何实际工作,但我觉得我必须以某种方式忽略这一点.宏是邪恶的化身,但"模板元编程"风靡一时.

那么,真正的区别是什么?模板如何避免#define引导你进入的危险,比如

在您不期望它们的地方难以理解的编译器错误?

代码臃肿?

跟踪代码有困难吗?

设置调试器断点?

Ferruccio.. 50

宏是一种文本替换机制.

模板是一种功能性的图灵完备语言,在编译时执行并集成到C++类型系统中.您可以将它们视为该语言的插件机制.



1> Ferruccio..:

宏是一种文本替换机制.

模板是一种功能性的图灵完备语言,在编译时执行并集成到C++类型系统中.您可以将它们视为该语言的插件机制.



2> Jeff B..:

这里有很多评论试图区分宏和模板.

是的 - 它们都是一样的:代码生成工具.

宏是一种原始形式,没有太多的编译器实施(比如在C中做对象 - 它可以完成,但它并不漂亮).模板更高级,并且有更好的编译器类型检查,错误消息等.

但是,每个人都有其他人没有的优势.

模板只能生成动态类类型 - 宏几乎可以生成您想要的任何代码(除了另一个宏定义).宏可以非常有用地将结构化数据的静态表嵌入到代码中.

另一方面,模板可以完成一些真正的FUNKY事情,这是宏不可能实现的.例如:

template class Unit
{
    double value;
public:
    Unit(double n)
    {
        value = n;
    }
    Unit operator+(Unit n)
    {
        return Unit(value + n.value);
    }
    Unit operator-(Unit n)
    {
        return Unit(value - n.value);
    }
    Unit operator*(double n)
    {
        return Unit(value * n);
    }
    Unit operator/(double n)
    {
        return Unit(value / n);
    }
    Unit operator*(Unit n)
    {
        return Unit(value * n.value);
    }
    Unit operator/(Unit n)
    {
        return Unit(value / n.value);
    }
    etc....
};

#define Distance Unit<1,0>
#define Time     Unit<0,1>
#define Second   Time(1.0)
#define Meter    Distance(1.0)

void foo()
{
   Distance moved1 = 5 * Meter;
   Distance moved2 = 10 * Meter;
   Time time1 = 10 * Second;
   Time time2 = 20 * Second;
   if ((moved1 / time1) == (moved2 / time2))
       printf("Same speed!");
}

该模板允许编译器动态地动态创建和使用模板的类型安全实例.编译器实际上在编译时执行模板参数数学运算,在每个唯一结果所需的位置创建单独的类.隐含的单位<1,-1>(距离/时间=速度)类型是在条件中创建和比较的,但从未在代码中明确声明.

显然,大学里的某个人已经定义了40多个参数的模板(需要参考),每个参数代表不同的物理单位类型.考虑一下这类课程的类型安全性,仅针对您的数字.


声明两个变量:距离d; 时间t; 如果距离和时间都是双精度数,则语句(d = t)和表达式(d == t)都是有效的.模板可以防止这种情况 - 为数值提供类型安全性.

3> rlerallut..:

它们由编译器解析,而不是由编译器之前运行的预处理器解析.

这是MSDN所说的:http: //msdn.microsoft.com/en-us/library/aa903548(VS.71).aspx

以下是宏的一些问题:

编译器无法验证宏参数是否为兼容类型.

扩展宏而不进行任何特殊类型检查.

i和j参数被评估两次.例如,如果任一参数具有后递增变量,则递增执行两次.

由于宏由预处理器扩展,因此编译器错误消息将引用扩展宏,而不是宏定义本身.此外,宏将在调试期间以扩展形式显示.

如果这对你来说还不够,我不知道是什么.


MSDN链接使用Min的模板,这几乎是最坏的"坏例子".请参阅Scott Meyer关于Min/Max模板的论文.http://www.aristeia.com/Papers/C++ReportColumns/jan95.pdf
显然你在技术上是正确的,但是说一个是由预处理器处理的,而另一个是由编译器处理的,并没有说明为什么一个比另一个好.
@Roddy你不公平.Min作为模板在其不完美状态下相当容易理解,并提供比宏更好的保护.Alexandrescu有一个解决最小/最大问题的解决方案,但它非常复杂,对我来说太复杂了.

4> Gregory Pako..:

答案是这么久,我不能总结一切,但:

例如,宏在功能模板没有确保类型安全时:编译器无法验证宏参数是否兼容类型 - 在实例化函数模板时编译器知道是否定义intfloat定义operator +

模板为元编程打开了大门(简而言之,评估事物并在编译时做出决定):在编译时,可以知道类型是整数还是浮点; 它是一个指针还是它的const限定等... 在即将到来的c ++ 0x中看到"type traits"

类模板具有部分特化

函数模板具有明确的完全特化,在您的示例中add(5, 3);可以实现add(5, 3);与宏不可能实现的不同

宏没有任何范围

#define min(i, j) (((i) < (j)) ? (i) : (j))- ij参数评估两次.例如,如果任一参数具有后递增变量,则递增执行两次

因为宏是由预处理器扩展的,编译器错误消息将引用扩展宏,而不是宏定义本身.此外,宏将在调试期间以扩展形式显示

等等...

注意:在极少数情况下,我更倾向于依赖可变参数宏,因为在c ++ 0x成为主流之前不存在可变参数模板. C++ 11现场直播.

参考文献:

C++ FAQ Lite:[35]模板

模板的优点

模板与宏(C++)



5> GManNickG..:

在最基本的层面上,是的,模板只是宏替换.但是,通过这种方式思考,你就会跳过很多东西.

考虑模板专业化,据我所知,你不能用宏来模拟.这不仅允许某些类型的特殊实现,它还是模板元编程中的关键部分之一:

template 
struct is_void
{
    static const bool value = false;
}

template <>
struct is_void
{
    static const bool value = true;
}

这本身就是你能做的很多事情的一个例子.模板本身是图灵完备的.

这忽略了非常基本的东西,例如范围,类型安全性,以及宏的问题.



6> catchmeifyou..:

.一个简单的反例:模板遵循命名空间,宏的忽略命名空间(因为它们是预处理器语句).

namespace foo {
    template 
    NumberType add(NumberType a, NumberType b)
    {
        return a+b;
    }

    #define ADD(x, y) ((x)+(y))
} // namespace foo

namespace logspace 
{
    // no problemo
    template 
    NumberType add(NumberType a, NumberType b)
    {
        return log(a)+log(b);
    }

    // redefintion: warning/error/bugs!
    #define ADD(x, y) (log(x)+log(y))

} // namespace logspace



7> Andru Luvisi..:

C++模板有点像Lisp宏(不是C宏),因为它们在已经解析的代码版本上运行,它们允许您在编译时生成任意代码.不幸的是,你正在编写类似于原始Lambda演算的东西,所以像循环这样的高级技术有点麻烦.有关所有血腥细节,请参阅Krysztof Czarnecki和Ulrich Eisenecker的Generative Programming.



8> Ryan..:

如果您正在寻找对该主题的更深入的处理,我可以将您转向每个人最喜欢的C++仇恨.这个人知道并且讨厌比我梦想的更多的C++.这同时使FQA令人难以置信的炎症和优秀的资源.


除了每当我看到FQA时,我都意识到他真的不知道他在说什么.他的许多抱怨是由于滥用C++.

9> moonshadow..:

模板是类型安全的.

模板化对象/类型可以是命名空间,是类的私有成员等.

模板化函数的参数不会在整个函数体中复制.

这些确实是一个大问题,可以防止大量的错误.

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