如何实施导出模板?

时间:2017-06-29 04:48:36

标签: c++ templates

导出模板是2011年之前的C ++中的一项功能,其中模板的实现将推迟到单独的源文件中。

According to this article,可以写"手册"通过手动指定实现文件中使用的每种类型来导出模板。因为这只会创建特定的符号 - 我相信与重载函数类似的方式 - 如何实现它是有道理的。

但我理解导出的模板(通过export关键字)是任意的。它可以允许传递任何类型的数据。

举个简单的例子:

template<typename T>
T add(T value1, T value2) {
    return value1 + value2;
}

如果T为intfloat或特别是std::string(以及任何其他超出+的类型,则此示例的程序集输出会有很大差异操作者)。

由于它完全是任意的,编译器如何实现这个关键字?

我的猜测是在链接时生成代码,这很可能需要一个自定义目标文件格式,包含代码的一些表示。但这也使链接器成为编译器,从而打破了preprocesser-compiler-linker分离。

3 个答案:

答案 0 :(得分:1)

2001年左右,EDG实施了export,而Comeau为我提供了早期版本。我确实能够实例化A<B<A<B<A<int> > > > >,其中A<T>在A.cpp中定义,B<T>在B.cpp中定义。显然,这需要某种形式的链接时代码生成。

这更令人惊讶,因为Comeau实际上使用了MSVC作为后端,而微软同时认为这是不可能的! (这就是我首先评估export的原因,WG21论文N1426)

答案 1 :(得分:0)

模板化事物只有在被编译的代码引用时才会实例化为具体类型。

此时编译器需要所有信息(结构定义,函数定义)才能生成代码。

如果编译器在导入结构时看到的唯一定义是

  export templat< ... > class foo;

它没有生成代码的机制,并且在请求类foo的功能时失败。

相反,在构建库时,编译器可以使用定义和实现,但是它无法看到库可以使用哪些类型。

可用的唯一(需要?)机制是头文件。这有定义和实现,并且不需要特殊的对象格式。

如果您明确地实例化模板的具体示例,则可以从库中导出这些示例,但仅适用于预先知道的类型。

答案 2 :(得分:0)

有一个神话,某些人期望导出的模板严格地单独编译,但没有证据表明其中的任何人(如果存在)都是委员会成员。

导出的模板确实是具有普通模板语义的普通模板。 (它们不是类似的O'Caml或Haskell模块。)

生成二进制代码的单独编译是基于ABI的 。为功能模板(相对于其实例化)使用ABI毫无意义。

C ++中的模板本质上类似于宏。并非基于令牌的C / C ++预处理程序宏类,因此它们无视C或C ++语法结构,但它们非常接近于基于替换的类(在语法实体上不是词法分析器杠杆)。

他们倾向于从实例化上下文中提取很多名称,这比我们想要的更多。那是因为在C ++中没有办法拥有“概念”元类型系统。 (而且C ++太复杂了,太不规则了,无法改装这样的东西。)

没有C ++模板的“概念”约定,C ++语言定义就不能严格限制在实例化上下文中可能要查找的名称:即使是a<b这样的显而易见的定义也没有C ++中的布尔值。按照惯例,它是一个由普通布尔类型(boolint表示的布尔值,但可以是任何东西(存在使返回类型成为类类型的用例)。

因此,与f(a<b)不同,即使模板中的f之类的东西也可能需要从实例化上下文中提取f(bool(a<b))

显然不可能单独进行模板的单独编译。从来没有导出模板的意图。

基于模板定义上下文和实例化上下文上下文来实例化模板。如果模板不是头文件,则仅表示编译器将考虑两个源文件。因此,这甚至不是一个严重的困难。 (当然有困难的问题,但是处理多个源文件不是一个。)

当然,这意味着C ++代码的“链接”将不是正常的链接:它将涉及为每个所需的模板实例化再次运行编译器,直到完成所有实例化。

(并且“运行时链接”将不包括此类模板-实例化链接,并且将不允许调用编译器来创建代码。)

我在这里提到的所有内容当时都很清晰明了。几乎没有证据表明,任何为语言的设计做出重大贡献的人都有不同的直觉。

实际上,最初C ++仅导出了模板,以至于它没有export关键字