添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
奋斗的企鹅  ·  Linux ...·  8 月前    · 
神勇威武的地瓜  ·  torch.bernoulli ...·  1 年前    · 

《C++编程思想》第15章(第300页)说明了原因:
模板定义很特殊。由template<…>处理的任何东西都意味着编译器在当时不为它分配存储空间(没有具体的函数时不会对模板实例化),它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。

定义一个类一般都是在头文件中进行类声明,在cpp文件中实现,但使用模板时应注意目前的C++编译器还无法分离编译,最好将实现代码和声明代码均放在头文件中。如:

template <class T>
class CTest
public:        
  T& GetValue();        
  void SetValue(const T& _Value);
protected:
  T m_Value;
test.cpp
template <class T>
T& CTest<T>::GetValue()
   return m_Value;  
template<class T>
void CTest<T>::SetValue(const T& _Value)
   m_Value   =   _Value;  

在这儿test.cpp中的内容应放在test.h中,否则在生成最终可执行程序时就会出现错误(在链接时会出错)。因为在编译时模板并不能生成真正的二进制代码,而是在编译调用模板类或函数的CPP文件时才会去找对应的模板声明和实现,在这种情况下编译器是不知道实现模板类或函数的CPP文件的存在,所以它只能找到模板类或函数的声明而找不到实现,而只好创建一个符号寄希望于链接程序找地址。但模板类或函数的实现并不能被编译成二进制代码,结果链接程序找不到地址只好报错了。

技巧15:模板定义的位置在哪里?是.cpp文件吗?

 通常情况下,你会在.h文件中声明函数和类,而将它们的定义放置在一个单独的.cpp文件中。但是在使用模板时,这种习惯性做法将变得不再有用,因为当实例化一个模板时,编译器必须看到模板确切的定义,而不仅仅是它的声明。因此,最好的办法就是将模板的声明和定义都放置在同一个.h文件中。这就是为什么所有的STL头文件都包含模板定义的原因。

 另外一个方法就是使用关键字“export”!你可以在.h文件中,声明模板类和模板函数;在.cpp文件中,使用关键字export来定义具体的模板类对象和模板函数;然后在其他用户代码文件中,包含声明头文件后,就可以使用该这些对象和函数了。例如

// output.h - 声明头文件
template<class T> void output (const T& t);
// out.cpp - 定义代码文件
#include <****>
export template<class T> void output (const T& t) {std::cerr << t;}
//main.cpp:用户代码文件
#include "output.h"
void main() // 使用output()
output(4);
output("Hello");

某种程度上,这有点类似于为了访问其他编译单元(如另一代码文件)中普通类型的变量或对象而采用的关键字extern。
  但是,这里还有一个不得不说的问题:并非所有的编译器都支持export关键字(我们最熟悉、最常用的两款编译器VS 和 GCC就是不支持export的典型代表)。对于这种不确定,最好的方法就是采用解决方案一:声明定义放在一起,虽然这在某种程度上破坏了C++编程的优雅性。

 分离编译模式(Separate Compilation Model)允许在一处翻译单元(Translation Unit)中定义(define)函数、类型、类对象等,在另一处翻译单元引用它们。编译器(Compiler)处理完所有翻译单元后,链接器(Linker)接下来处理所有指向 extern 符号的引用,从而生成单一可执行文件。该模式使得 C++ 代码编写得称心而优雅。

 然而该模式却驯不服模板(Template)。标准要求编译器在实例化模板时必须在上下文中可以查看到其定义实体;而反过来,在看到实例化模板之前,编译器对模板的定义体是不处理的——原因很简单,编译器怎么会预先知道 typename 实参是什么呢?因此模板的实例化与定义体必须放到同一翻译单元中。

  以优雅著称的 C++ 是不能容忍有此“败家玩意儿”好好活着的。标准 C++ 为此制定了“模板分离编译模式(Separation Model)”及 export 关键字。然而由于 template 语义本身的特殊性使得 export 在表现的时候性能很次。编译器不得不像 .net 和 java 所做的那样,为模板实体生成一个“中间伪代码(IPC,intermediate pseudo - code)”,使得其它翻译单元在实例化时可找到定义体;而在遇到实例化时,根据指定的 typename 实参再将此 IPC 重新编译一遍,从而达到“分离编译”的目的。因此,该标准受到了几乎所有知名编译器供应商的强烈抵制。
  谁支持 export 呢?Comeau C/C++ 和 Intel 7.x 编译器支持。而以“百分百支持 ISO ”著称的 VS 和 GCC 却对此视而不见。真不知道这两大编译器“百分百支持”的是哪个版本的 ISO。在 VS 2008 中,export 关键字在 IDE 中被标蓝,表示 VS IDE 认识它,而编译时,会用警告友情提示你“不支持该关键字”,而配套的 MSDN 9 中的 C++ keywords 页则根本查不到该关键字;而在 VS 2010 中,就没那么客气了,尽管 IDE 中仍然会将之标蓝,但却会直截了当地报错。C++11已经取消使用关键字export。

原文链接:https://blog.csdn.net/u011846123/article/details/90674912 近在仿写stl,发现stl源码模板声明定义写在一起实在很不优雅。自己尝试用“传统”方法,及在.h文件里声明,在.cpp文件里定义,然后在main函数里包含.h头文件,这样会报链接错误。这是因为函数模板要被实例化后才能成为真正的函数,在使用函数模板的源文件包含函数模板的头文件,如果该头文件只有声明,没有定义,那编译器无法实例化该模板,终导致链接错误。   上面这句话有点抽象。要理解为什么会出错,首先要理解用传统方法写非模板函数时,编译器是怎么运作的。举个例子 //—————test.h——————-// void f();//这里声明一个函数f //—————test.cpp 原文出处:https://www.codeproject.com/Articles/48575/How-to-Define-a-Template-Class-in-a-h-File-and-Imp​www.codeproject.comc++常见的过程是将类定义放在一个c++头文件,将实现放在一个c++源文件。然后,源文件成为项目的一部分,这意味着它是单独编译的。但是当我们为模板实现这个过... C++ 需要模板函数的定义声明要放在一起,这样才能根据调用需要选择编译具体的实例。如果我们需要多种实例,每个实例要编译一次,就需要编译多次。在模板函数实现妥当以后,当我们在其它文件使用某些模板函数的时候,基本所有实例都会被重新编译。如果每次编译时间过长,势必会停滞我们的思维,拖长开发进度。所以在模板函数实现妥当以后,我们希望他只编译一次,在非当前模块被修改时,他也不会被重新编译。这篇博客就是介绍 虽然我们遇到的绝大多数情况下,模板函数的声明定义都放在头文件,但我想肯定有人和我一样,想知道是否可以分开存放。动手实验后,会发现有的可以,有的会报错,其实,这和编译器有关。         要弄清楚这个问题,首先要解决两个问题。         第一,为什么要把函数的声明放在头文件,而定义放在.cpp文件? 除了隐藏代码之外,如果将函数的定义也放入头文件,那么每个include了这 今天写一个模板类,用MingW翻译,出现undefined reference to `RBTreeNode<int, int>::RBTreeNode..... RBTreeNode是一个模板类,可以见后面的代码。其声明放在了.h定义放在了.cpp。 main.cpp引用BRTreeNode类的构造函数,出现Link Error. 简单分析一下: 共有三个文件RBNod... 在使用类模板技术时,可在.h实现,也可在.h和.cpp分开实现,若用.h实现,不要在文件加入非类模板代码,可避免重写定义错误..       2009年7月25日23时58分58秒 //////////////////////////////////////////////////////////////////////////////////////////////////////// http://www.gois.ws/showfile.asp?id=460:0:0如何组织编写模板程序 发表日期: 1/21/2003 12:28:58 PM 发表人: Nemanja Trifunovic 前言常遇到询问使用模板到底是否容易的问题,我的回答是:“模板的使用是容易的,但组织编写却不容易”。看看我们几乎每天都能遇到的模板类吧,如STL, ATL, WTL, 以及Boost的 总结下c++模板相关的基础知识,便于查阅。 模板定义以关键字template开始,后跟一个模板参数列表,这是一个逗号分隔的一个或者多个模板参数的列表,用小括号和大括号包围起来。 模板是个半成品,模板编译通过但是使用错误仍然会报错; 可以将模板看作是编译期函数; 运行期函数的参数要为一个对象(不能模板);编译期函数的参数可以是模板模板声明必须包含模板参数: // 声明但是不定义compare和Blob template<typename T> int compare(cons 最近实现一个单链表,使用模板声明定义。 问题描述: 单链表模板声明实现在.h 文件,该模板定义实现在.cpp文件,发现VS2019编译失败,错误信息如下所示: 原因分析: 以前写模板函数或者模板类,定义实现都在.h文件实现,所以没有出现过这个问题,现在出现这种无法解析的外部符号错误,一时没想到是模板函数或模板类的声明定义不能分离,即都要在.h文件实现声明定义,这里的分离指的就是分别在.h文件和.cpp文件实现声明定义。 至于为什么模板函数或模板类的声明实现不能分离,必 参考https://blog.csdn.net/mincheat/article/details/77987740 一般情况,模板函数被外部其他引用会提示找不到函数,原因是: 编译本身这个cpp的时候,没有发现有引用的地方,那么就不会被编译,而编译引用这个模板函数的其他cpp的时候,要直接调用这个函数,就会发现这个函数没有编译,没有实现,所以报错,找不到该函数。 因此心生一计,是否可以写一个额外函数在本cpp将该模板函数使用一下,外部就可以找到此函数了。 适用场景:希望对外声明提供的头文件简单并隐藏实现