C++ 中的自由定理:模板是否天生无知且与其未知类型的对象保持中立?

Free theorems in C++: are templates inherently ignorant and neutral with their objects of unknown types?

著名的 Haskell 如果我们有一个没有具体类型的函数,我们可以推断出一些关于它的行为,例如

f : a -> a

永远是身份。

使用 Java 泛型我们无法证明泛型函数具有特定行为,因为我们可以使用 instanceofObject 基础 class 上的方法来变通限制,但是如果我看到带有签名

的方法
<T> List<T> reverse(List<T> list)

假设该函数不会使用类型 T 的任何属性是合理的。

模板化 C++ 函数的类型签名似乎没有提供有关其实现的任何提示。该标准是否有任何现有或建议的功能,可以让我们编写函数签名,在 C++ 中提供类似的推论?例如,一些表示 "This function works for absolutely any type".

的方式

也许您指的是 C++20 约束和概念:https://en.cppreference.com/w/cpp/language/constraints:

Class templates, function templates, and non-template functions (typically members of class templates) may be associated with a constraint, which specifies the requirements on template arguments, which can be used to select the most appropriate function overloads and template specializations.

Named sets of such requirements are called concepts. Each concept is a predicate, evaluated at compile time, and becomes a part of the interface of a template where it is used as a constraint.

请注意,此功能是在 C++20 中添加的,GCC 仅部分支持。

不,没有。模板非常ad-hoc。本质上,它们只是宏,其扩展由类型信息驱动。模板是否可以用给定类型实例化几乎完全基于扩展来定义。事实上,允许实例化一个模板,只要不使用其他位,它的扩展只有一部分会 type-check。

扩展是否 type-checks 取决于 C++ 的许多特性、语法和语义。由于重载、隐式强制转换、强制转换和模板特化等有问题的特性,参数化 属性 不可能给你自由定理。

有些评论提到了概念。然而,概念并没有改变这一点 属性——它们允许明确地限制实例化,但和以前一样,没有这样的限制并不意味着它适用于所有东西。

模板可不是什么普通的东西。它不能像一个一样编译,因为 C++ 没有(并且可能永远不会)任何有意义的模板概念作为调用者和被调用者之间的接口和静态契约,例如函数的 "forward declaration" 。想象一个世界,其中任何函数实际上都是一个宏(几乎像可怕的 #define 风格,但行为不那么恶劣)并且必须扩展才能进行类型检查。这几乎就是模板。

这也是模板如此强大的原因!模板形成图灵完备语言,因为模板实例化可以递归。这是一个可怕的 sub-language 所以发明 constexpr 是为了在没有递归模板的情况下为递归编译时表达式提供一个干净的 sub-language。

你只能根据模板实例化来推理。 "signature" 什么也没告诉你。 就像干净的 lisp 和宏一样,模板永远不会被正确地单独编译,即使使用 "export template" 也不行,这在链接后需要第二个 运行 编译器。

顺便说一句,一位 C++ 标准委员会成员暗示,"export template" 被卖给 C++ 专家作为模板的适当单独编译,就好像它们是普通的非内联函数一样,是一个骗局;从来没有 C++ 专家相信这一点。

这就是 C++20 中的概念应该做的事情。当然,所有现有模板都是不受约束的(通过 enable_if 欺骗或类似手段除外),因此明确使用 Any 概念可能有助于记录意图。

也就是说,C++ 无论如何都没有参数多态性:没有单一的方法来操作完全任意类型的“值”,因为没有指向引用的指针。)即使写 T() non-trivial 关于类型的假设。因此,(草案)C++20 标准库提供了像 Movable 这样的“通用值”概念,这些概念实际上很有用,但提供的自由定理较少。