我试图找出什么时候应该使用C++20模板约束。
目前我只用约束来解除模板过载。
然而,还有很多模板是没有重载的。几乎所有的模板都有关于模板类型特征的隐性期望。
作为一个例子,让我们假设一个函数模板,它隐式地期望一个容器类型,并通过调用一个 T::size()
方法,并使用 T::operator[]
操作符.通常情况下,如果传递的类型没有提供这样的操作符,我会得到一个编译错误。T::size()
的方法,或 T::operator[]
. 不过我还是可以添加显式约束来表达所需的功能。
在哪些情况下,依靠隐式编译错误而不是显式约束可能是致命的?除了把约束作为文档的一部分之外,显式约束比隐式需求有什么优势?
实际上,在C++代码中,有概念的倾向是,要么有重载约束函数,是为了通过参数依赖名查找,要么有约束调用操作符的漏斗。
没有不是约束的无模板函数(*)。而寓意最终可能是没有不应该被重载的自由函数。
所有不约束的模板函数和不应该被重载的模板函数最好用functor对象代替。我认为有3个原因。
在一个不应该被重载的自由函数中加入约束是适得其反的:加入约束实际上为不需要的重载打开了更多的空间。
另一方面,在客户端代码中,函数调用操作符不能被重载。
一旦在作用域中声明了一个functor对象,就会禁用依赖参数的名称查找。
最后,范围库更进一步。对于每一个应该被客户端重载的函数,该库都声明并使用了漏斗对象,以检查将被调用的重载是否满足所有重载都应该满足的一些约束条件。例如 std::range::begin
. 在库中,这些漏斗函数被称为 自定义点对象. 这可能是最安全的方法,但实现起来相当漫长。
(*) 参见Davis Herring的评论,关于漏斗对象不能作为选项的特殊情况。