将C++;编译器是否为每种模板类型生成代码? 关于C++中的模板,我有两个问题。让我们想象一下,我已经编写了一个简单的列表,现在我想在我的程序中使用它来存储指向不同对象类型(a*,B*…ALot*)的指针。我的同事说,对于每种类型,都会生成一段专用的代码,即使所有指针实际上大小相同

将C++;编译器是否为每种模板类型生成代码? 关于C++中的模板,我有两个问题。让我们想象一下,我已经编写了一个简单的列表,现在我想在我的程序中使用它来存储指向不同对象类型(a*,B*…ALot*)的指针。我的同事说,对于每种类型,都会生成一段专用的代码,即使所有指针实际上大小相同,c++,templates,C++,Templates,如果这是真的,有人能解释一下原因吗?例如,在java中泛型与C++中指针的模板有相同的用途。泛型仅用于编译前类型检查,并在编译前进行精简。当然,同样的字节码用于所有东西 第二个问题是,是否还会为char和short生成专用代码(考虑到它们都具有相同的大小,并且没有专门化) 如果这有什么区别的话,我们现在讨论的是嵌入式应用程序 我发现了一个类似的问题,但它并没有完全回答我的问题: 非常感谢 答案是可能。通常,每个 模板是唯一的类型,具有唯一的实现,并且 将产生一个完全独立的代码实例。 合并实例是可

如果这是真的,有人能解释一下原因吗?例如,在java中泛型与C++中指针的模板有相同的用途。泛型仅用于编译前类型检查,并在编译前进行精简。当然,同样的字节码用于所有东西

第二个问题是,是否还会为char和short生成专用代码(考虑到它们都具有相同的大小,并且没有专门化)

如果这有什么区别的话,我们现在讨论的是嵌入式应用程序

我发现了一个类似的问题,但它并没有完全回答我的问题:


非常感谢

答案是可能。通常,每个 模板是唯一的类型,具有唯一的实现,并且 将产生一个完全独立的代码实例。 合并实例是可能的,但会被考虑 “优化”(根据“仿佛”规则),以及此优化 它没有广泛传播

关于与Java的比较,有几点 要记住:

  • 默认情况下,C++使用值语义。一个
    std::vector
    ,用于 例如,将实际插入副本。以及你是否 复制
    short
    double
    确实会对 生成的代码。在Java中,
    short
    double
    将被装箱, 生成的代码将以某种方式克隆一个已装箱的实例; 克隆不需要不同的代码,因为它调用虚拟
    对象的函数
    ,但实际复制会执行

  • C++比Java强大得多。特别是,它允许 比较函数的地址之类的东西,它需要 模板的不同实例化中的函数 不同的地址。通常,这不是重点, 我很容易想象一个编译器有一个选项 忽略这一点并合并 在二进制级别相同。(我认为VC++有如下功能 这个。)

另一个问题是C++中模板的实现 必须存在于头文件中。当然,在Java中, 一切都必须永远存在,所以这个问题影响到所有人 类,而不仅仅是模板。当然,这是一个 Java不适合大型应用程序的原因。但是 这意味着您不想在一个应用程序中使用任何复杂的功能 模板;这样做失去了C++的主要优点之一。 与Java(和许多其他语言)相比。事实上,事实并非如此 很少,在模板中实现复杂功能时, 要使模板从非模板类继承,请执行以下操作: 大部分实现都是以

void*
的形式进行的。虽然 根据
void*
实现大型代码块从来都不是一件容易的事 有趣的是,它的优点是两者兼而有之 客户端的世界:实现隐藏在编译的 以任何方式、形状或方式对客户不可见的文件

关于C++中的模板,我有两个问题。让我们想象一下,我已经编写了一个简单的列表,现在我想在我的程序中使用它来存储指向不同对象类型(a*,B*…ALot*)的指针。我的同事说,对于每种类型,都会生成一段专用的代码,即使所有指针实际上大小相同

是的,这相当于编写这两个函数

一些链接器将检测相同的函数,并消除它们。有些库知道它们的链接器没有这个特性,所以将公共代码分解成单个实现,只在公共代码周围留下一个强制转换包装器。也就是说,一个
std::vector
专业化可以将所有工作转发给一个
std::vector
,然后在退出时进行铸造

现在,comdat折叠是很微妙的:它相对容易使你认为是相同的函数,但最终不是相同的,所以生成了两个函数。例如,您可以通过
typeid(x).name()
打印typename。现在,函数的每个版本都是不同的,并且不能消除它们

在某些情况下,您可能会这样做,认为它是一个运行时属性不同的,因此将创建相同的代码,并且消除了相同的函数——但是智能C++编译器可能会找出您所做的,使用IAS规则并将其转换成编译时检查,并阻止不完全相同的函数被视为相同

如果这是真的,有人能解释一下原因吗?例如,在java中泛型与C++中指针的模板有相同的用途。泛型仅用于每个编译类型的检查,并在编译之前进行精简。当然,同样的字节码用于所有东西

不,他们不是。泛型大致相当于C++类型的擦除技术,比如什么代码> STD::函数< /C> >存储任何可调用对象。在C++中,类型擦除通常是通过模板完成的,但不是所有模板的使用都是类型擦除! <> > C++对模板的处理不是本质类型的擦除,一般不可能用java泛型来处理。 <>在C++中,可以使用模板创建指针类型的擦除容器,但是<>代码STD::vector < /COD>不这样做——它创建了指针的实际容器。这样做的好处是
std::vector
上的所有类型检查都是在编译时完成的,因此不必进行任何运行时检查:安全类型擦除
std::vector
可能需要运行tim
std::cout << x << "\n";