【发布时间】:2021-08-04 18:10:45
【问题描述】:
所以,作为一个着迷的初学者,我想知道一些模板元编程的最佳实践。在进行更复杂的编译时计算时,我遇到的一件事是编译器默认使用的小递归深度(因为它们实例化了模板,所以效率低下),以及即使是简单的计算也可能造成的损失。例如,在使用追加样式时,编写整数序列生成器(像 python 的 range() 一样工作)受到极大限制。也就是说,我怀疑它在 O(n^2) 时间(由于复制)以高系数运行(很难说,因为这取决于 GCC 参数包传播的实现)。然而,连续递归给出了线性深度。微不足道地,分而治之的方法解决了这个问题,大约(通过与以前相同的混淆原理)提供O(nlog(n)) 效率,具有大约O(log(n)) 深度的积极副作用,来自线性O(n) 深度与先验。
既然描述了我的基本头部空间,我将询问来自 GCC 源代码的这些标准库实现。虽然它们是辅助函数,但这不是让减少模板实例深度变得更加重要吗?
/// add_const
template<typename _Tp>
struct add_const
{ typedef _Tp const type; };
/// add_volatile
template<typename _Tp>
struct add_volatile
{ typedef _Tp volatile type; };
/// add_cv
template<typename _Tp>
struct add_cv
{
typedef typename
add_const<typename add_volatile<_Tp>::type>::type type;
};
不能通过不相互调用模板来避免一些深度(和视觉上的麻烦):(并且还使用类型别名哈哈)
// add_const
template <typename _Tp>
struct add_const { using type = const _Tp; };
// add_volatile
template <typename _Tp>
struct add_volatile { using type = volatile _Tp; };
// add_cv
template <typename _Tp>
struct add_cv { using type = volatile const _Tp; };
如果第二种类型有问题,或者差异不是很重要,请告诉我。非常感谢!
【问题讨论】:
-
将重复的代码放在一个地方(不重复)通常比在编译器上轻松播放更有益。
-
“视觉头痛”在旁观者的眼中。写 cv 是 c 和 v 的组合也是有道理的。至于性能,没有递归或任何涉及的东西,所以无论哪种方式都是 O(1)。
-
对
add_cv使用两个现有模板的一个优点是它允许使用add_const或add_volatile的特化,而不必专门化add_cv。 -
我尽量不要太看重标准库代码,也不建议将其用作优秀代码的示例。编写主流库实现的人有两个主要关注点:1)它产生标准描述的行为,2)它非常高效。在不违反 1 的情况下支持 2,他们经常做一些令人讨厌的事情并且可以侥幸逃脱,因为他们知道库附带的编译器以及它将密切运行的广泛硬件,并且可以完全接受实现定义的行为和出于未定义的行为而滥用生活地狱
-
YouTube 上有一些主要 C++ 会议的演示视频,包括关于模板元编程性能的讨论。寻找this guy
标签: c++ templates gcc metaprogramming