在 D 中帮助模板元编程的两个最重要的事情是模板约束和static if
- 从理论上讲,C++ 可以添加这两者,并且这将使其受益匪浅。
模板约束允许您在模板上放置一个条件,该条件必须为真才能实例化模板。例如,这是其中一位的签名std.algorithm.find
的重载:
R find(alias pred = "a == b", R, E)(R haystack, E needle)
if (isInputRange!R &&
is(typeof(binaryFun!pred(haystack.front, needle)) : bool))
为了能够实例化此模板化函数,类型R
必须是由下式定义的输入范围std.range.isInputRange
(so isInputRange!R
必须是true
),并且给定的谓词需要是一个二元函数,它使用给定的参数进行编译并返回一个可以隐式转换为的类型bool
。如果模板约束条件的结果是false
,那么模板将无法编译。这不仅可以保护您免受在 C++ 中模板无法使用给定参数进行编译时出现的令人讨厌的模板错误的影响,而且还可以使您可以根据模板约束重载模板。例如,还有另一个过载find
这是
R1 find(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
if (isForwardRange!R1 && isForwardRange!R2
&& is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool)
&& !isRandomAccessRange!R1)
它采用完全相同的参数,但其约束不同。因此,不同的类型使用同一模板化函数的不同重载,并且最佳实现find
可用于每种类型。在 C++ 中没有办法干净地完成这类事情。只要稍微熟悉一下典型模板约束中使用的函数和模板,D 中的模板约束就相当容易阅读,而您需要在 C++ 中进行一些非常复杂的模板元编程才能尝试这样的事情,而普通程序员却做不到这一点都能够理解,更不用说自己亲自去做了。 Boost 就是一个典型的例子。它做了一些令人惊奇的事情,但它非常复杂。
static if
进一步改善情况。就像模板约束一样,任何可以在编译时评估的条件都可以与它一起使用。例如
static if(isIntegral!T)
{
//...
}
else static if(isFloatingPoint!T)
{
//...
}
else static if(isSomeString!T)
{
//...
}
else static if(isDynamicArray!T)
{
//...
}
else
{
//...
}
哪个分支被编译取决于哪个条件首先评估为true
。因此,在模板中,您可以根据模板实例化的类型或基于可以在编译时评估的任何其他内容来专门化其实现的各个部分。例如,core.time
uses
static if(is(typeof(clock_gettime)))
根据系统是否提供不同的方式编译代码clock_gettime
或不(如果clock_gettime
在那里,它使用它,否则它使用gettimeofday
).
我见过的 D 对模板进行改进的最明显的例子可能是我的团队在工作中在 C++ 中遇到的一个问题。我们需要根据给定的类型是否派生自特定基类来以不同的方式实例化模板。我们最终使用了基于的解决方案这个堆栈溢出问题 https://stackoverflow.com/questions/2631585/c-how-to-require-that-one-template-type-is-derived-from-the-other。它有效,但仅测试一种类型是否派生于另一种类型是相当复杂的。
然而,在 D 中,您所要做的就是使用:
操作员。例如
auto func(T : U)(T val) {...}
If T
可以隐式转换为U
(就像如果T
源自U
), then func
将编译,而如果T
不能隐式转换为U
,那么就不会了。That简单的改进甚至可以使基本的模板专业化变得更加强大(即使没有模板约束或static if
).
就我个人而言,除了容器和偶尔使用的函数之外,我很少在 C++ 中使用模板<algorithm>
,因为它们使用起来非常痛苦。它们会导致丑陋的错误,并且很难做任何花哨的事情。要完成任何稍微复杂的事情,您都需要非常熟练地使用模板和模板元编程。不过,有了 D 中的模板,它非常简单,我一直在使用它们。这些错误更容易理解和处理(尽管它们仍然比非模板化函数通常出现的错误更糟糕),而且我不必弄清楚如何通过花哨的元编程强制语言执行我想要的操作。
C++ 没有理由不能获得 D 所拥有的大部分能力(如果它们能够解决这些问题,C++ 概念将会有所帮助),但直到它们添加了类似于模板约束和构造的基本条件编译和static if
对于 C++,C++ 模板在易用性和功能方面无法与 D 模板相比。