何时/为什么(如果有的话)我应该考虑进行通用编程/元编程

Ama*_*wal 17 c++ templates metaprogramming generic-programming

恕我直言,OOPS,设计模式是有道理的,我已经能够实际应用它们.

但是当谈到 Modern C++类的"泛型编程/元编程"时,我感到很困惑.

- 这是一种新的编程/设计范式吗?

- 它仅限于"图书馆开发"吗?如果没有,那么设计/编码情况需要使用元编程/泛型编程.

- 使用模板意味着我正在进行通用编程吗?

我在这个主题上搜索了很多,但没有完全掌握大图.另见这篇文章.


在阅读了这里的讨论之后,到目前为止,我确信(可能仍然不正确):

a)通用编程和元编程是两个不同的概念.

jal*_*alf 30

元编程是一个非常奇特的主题.了解它很有趣,它是一个强大的工具,偶尔你会发现它很有用.但它永远不会是您工具箱中最常用的工具.有时候,您可能希望代码对一系列具有不同属性的不相关类型起作用,这就是元编程的用武之地.通过一些技巧,您可以编写一个函数的重载,只有在参数类型为完整时才可用,或者如果它是指针,或者它是X,Y或Z型(可能忽略Z上的常量).

它本质上是用类型编程的.通常情况下,您的程序可以执行诸如获取两个数字并生成第三个数字之类的操作,或者告诉您数字是否满足某些要求.元编程可以采用两种类型并产生第三种类型,或者告诉您类型是否满足某些要求.是的,它可能在图书馆开发中最有用.但话说回来,大多数代码都可以被视为库代码.你可以说main()函数之外的所有东西都是库代码.

通常,如果您想通过元编程来解决问题,您可能希望使用相关的boost库来完成繁重的工作.Boost.TypeTraits,当然还有Boost.Mpl可以为你简化一些事情.但这不是你需要知道的事情,而且这不是你经常需要的东西.

通用编程是相关的(并且在某些情况下可能使用元编程实现非常通用,例如标准库使用元编程触摸将原始指针转换为有效的迭代器,这是"迭代器"概念通用所必需的) ,但不完全一样.它的使用范围更广泛.

每次实例化时std::vector,都使用泛型编程.每次使用一对迭代器处理一系列值时,都使用泛型编程.通用编程只是这样一种想法,即您的代码应尽可能通用,并且无论放入何种类型,都应该工作.std :: vector不需要包含的类型来实现"ICanBeContained"接口(还记得Java是否需要从Object派生所有内容以便将它存储在容器类中?这意味着原始类型被装箱,并且我们失去了类型安全.这不是通用的,这是一个毫无意义的限制.)

使用迭代器迭代序列的代码是通用的,可以与任何类型的迭代器一起使用,甚至可以使用普通指针.

通用编程非常有用,并且通常可以在很大程度上取代OOP.(参见上面的例子.为什么我会编写一个需要包含类型来实现接口的容器,如果我可以避免这种限制?)

通常,当您在OOP中使用接口时,不允许在运行时更改类型(虽然当然也会不时发生),但是允许您在编译时交换另一种类型(可能注入一个测试期间的模拟对象,而不是使用完整的实现),或仅仅是为了解耦两个类.通用编程可以做到这一点,而无需您完成定义和维护界面的繁琐工作.在这些情况下,通用编程意味着您必须编写和维护更少的代码,并且您可以获得更好的性能和更好的类型安全性.所以,是的,您应该在家中使用通用编程.C++不是一个非常好的OOP语言.如果你想严格遵守OOP,你应该切换到Java或其他更多OOP固定的语言.C++ 允许您编写OO代码,但它通常不是最佳解决方案.这就是为什么几乎整个标准库都依赖于泛型编程而不是OOP的原因.标准库中的遗传或多态性非常少.他们不需要它,代码变得更简单,没有它就更强大.

回答你的其他问题,是的,通用编程几乎是一个单独的范例.模板元编程不是.这是一种操作类型系统的相当具体的技术,非常擅长解决少数问题.要被视为一种范式,我认为它必须更加普遍有用,并且您可以使用的方法基本上用于所有功能,OO或通用编程.

我认为xtofl真的把它钉在了它上面:通用编程就是让你的代码类型 - 不知道.(std :: vector不关心,或者需要知道它中存储了什么类型.它只是起作用.)

另一方面,元编程是关于类型计算.给定类型T0和T1,我们可以定义类型T2,就像我们如何,给定整数N0和N1,我们可以定义一个N2,它是N0和N1的总和.

Boost.Mpl库有一个明显的例子.在普通代码中,如果你有整数N0,N1和N2,你可以创建一个包含这三个值的std :: vector.然后我可以使用其他算法来计算索引,然后提取存储在向量中该位置的值.

给定类型T0,T1和T2,我们可以创建一个包含这三种类型的mpl :: vector .我现在可以使用其他算法在编译时计算索引,并提取存储在向量中该位置的类型.

  • 感谢显示元和通用之间差异的客观意见! (2认同)

xto*_*ofl 11

你真的必须区分泛型编程(有点类型 - 不知道)和元编程,这是在类型系统中进行计算的完全合法的方法.

当您在许多代码中找到可推广的模式时,通用编程非常有用.如果模式的差异不仅存在于变量值中,而且存在于不同类型中,则泛型编程对于重构代码很有用.

元编程适用于完全不同的领域.这个领域确实很新,需要一些你自己的探索.这很有趣!

一个非常有用且常见的元编程模式是特征/政策概念.


Rod*_*ddy 10

C++模板元编程是一种功能强大的代码混淆技术,适用于各种应用:

  • 当您想编写团队中没有其他人可以理解的代码时
  • 如果您想要在编写代码后7天内无法理解的代码
  • 当代码性能对您而言比可维护性更重要时
  • 如果您希望能够将"模板元编程"列为简历中的技能.
  • 当你需要编写不太可能在许多真实编译器上工作的代码时
  • 如果您宁愿吃剃刀刀片而不是使用预处理器宏

另一个案例:

  • 如果您想了解Boost库是如何工作的,或者您想要为它们做出贡献.

"通用编程"(想想STL容器,auto_ptrs等)之间的区别,这是C++模板旨在实现的目标和"模板元编程"(使用模板系统让编译器为您有效地"运行算法")是重要.

我赞成第一个,但很难看到后者带来的实际好处.

  • 你可以对OOP说同样的话.当人们过分使用类层次结构并隐藏8个接口后面的所有内容并且每个函数都是虚拟的时,您也可以实现上述所有功能.无论如何,看看tydok的例子,并告诉我如果argumnt类型是ISwappable而不是模板类型T它会变得更易读和更易于维护.当然它不会,这就是通用编程很有用的原因. (2认同)

Ale*_*lcu 5

对于高级模板和技术,我推荐:Andrei Alexandrescu撰写的现代C++设计

C++是一种严格的语言,几乎没有运行时内省功能.您将遇到的许多麻烦都可以通过模板处理.此外,模板语言是图灵完备的,可以在编译时生成复杂的数据结构和预先计算值等.对于许多场景,它可能比它值得更麻烦.