精华内容
下载资源
问答
  • 类模板实例化问题

    千次阅读 2016-12-05 15:43:03
    模板函数在声明的时候, 其实并不存在,函数地址也就无从谈起了,而导出到动态链接库的函数都需要有地址 (动态链接库不能将模板类导出,因为没法生成实例) 如果把模板类的声明和...原因是模板类实例化要分成两个步

    模板函数在声明的时候, 其实并不存在,函数地址也就无从谈起了,而导出到动态链接库的函数都需要有地址

    (动态链接库不能将模板类导出,因为没法生成实例)

    如果把模板类的声明和定义都放在头文件中。需要用到模板类的时候,只需要包含该头文件,然后进行实例化。

    如果模板类的声明和定义分别放在头文件和源文件中。当实例化的时候,只包含头文件会发证链接错误。

    原因是模板类的实例化要分成两个步骤,模板的特例化和特例的实力化。

    编译器在编译阶段,由于没有定义,所以编译器不能生成具体的模板特例,但是这并不会报错误,编译器将把问题抛给链接器来做。在编译源文件的时候,程序找不到该模板的特例,只是有模板而已,所以无法生成对象。所以会发生错误。

    以下转自牛人blog

    =================

    前言

      常遇到询问使用模板到底是否容易的问题,我的回答是:“模板的使用是容易的,但组织编写却不容易”。看看我们几乎每天都能遇到的模板类吧,如STL, ATL, WTL, 以及Boost的模板类,都能体会到这样的滋味:接口简单,操作复杂。

      本文对象是那些熟悉模板但还没有很多编写模板经验的程序员。本文只涉及模板类,未涉及模板函数。但论述的原则对于二者是一样的。

      问题的产生

      通过下例来说明问题。例如在array.h文件中有模板类array:

      // array.h

      template <typename T, int SIZE>

      class array

      {

      T data_[SIZE];

      array (const array& other);

      const array& operator = (const array& other);

      public:

      array(){};

      T& operator[](int i) {return data_[i];}

      const T& get_elem (int i) const {return data_[i];}

      void set_elem(int i, const T& value) {data_[i] = value;}

      operator T*() {return data_;}

      };

      然后在main.cpp文件中的主函数中使用上述模板:

      // main.cpp

      #include "array.h"

      int main(void)

      {

      array<int, 50> intArray;

      intArray.set_elem(0, 2);

      int firstElem = intArray.get_elem(0);

      int* begin = intArray;

      }

      这时编译和运行都是正常的。程序先创建一个含有50个整数的数组,然后设置数组的第一个元素值为2,再读取第一个元素值,最后将指针指向数组起点。

      但如果用传统编程方式来编写会发生什么事呢?我们来看看:

      将array.h文件分裂成为array.h和array.cpp二个文件(main.cpp保持不变)

      // array.h

      template <typename T, int SIZE>

      class array

      {

      T data_[SIZE];

      array (const array& other);

      const array& operator = (const array& other);

      public:

      array(){};

      T& operator[](int i);

      const T& get_elem (int i) const;

      void set_elem(int i, const T& value);

      operator T*();

      };

     // array.cpp

      #include "array.h"

      template<typename T, int SIZE> T& array<T, SIZE>::operator [](int i)

      {

      return data_[i];

      }

      template<typename T, int SIZE> const T& array<T, SIZE>::get_elem(int i) const

      {

      return data_[i];

      }

      template<typename T, int SIZE> void array<T, SIZE>::set_elem(int i, const T& value)

      {

      data_[i] = value;

      }

      template<typename T, int SIZE> array<T, SIZE>::operator T*()

      {

      return data_;

      }

      编译时会出现3个错误。问题出来了:

      为什么错误都出现在第一个地方?

      为什么只有3个链接出错?array.cpp中有4个成员函数。

      要回答上面的问题,就要深入了解模板的实例化过程。

      模板实例化

      程序员在使用模板类时最常犯的错误是将模板类视为某种数据类型。所谓类型参量化(parameterized types)这样的术语导致了这种误解。模板当然不是数据类型,模板就是模板,恰如其名:

      编译器使用模板,通过更换模板参数来创建数据类型。这个过程就是模板实例化(Instantiation)。

      从模板类创建得到的类型称之为特例(specialization)。

      模板实例化取决于编译器能够找到可用代码来创建特例(称之为实例化要素,

      point of instantiation)。

      要创建特例,编译器不但要看到模板的声明,还要看到模板的定义。

      模板实例化过程是迟钝的,即只能用函数的定义来实现实例化。

      再回头看上面的例子,可以知道array是一个模板,array<int, 50>是一个模板实例 - 一个类型。从array创建array<int, 50>的过程就是实例化过程。实例化要素体现在main.cpp文件中。如果按照传统方式,编译器在array.h文件中看到了模板的声明,但没有模板的定义,这样编译器就不能创建类型array<int, 50>。但这时并不出错,因为编译器认为模板定义在其它文件中,就把问题留给链接程序处理。

      现在,编译array.cpp时会发生什么问题呢?编译器可以解析模板定义并检查语法,但不能生成成员函数的代码。它无法生成代码,因为要生成代码,需要知道模板参数,即需要一个类型,而不是模板本身。

      这样,链接程序在main.cpp 或 array.cpp中都找不到array<int, 50>的定义,于是报出无定义成员的错误。

      至此,我们回答了第一个问题。但还有第二个问题,在array.cpp中有4个成员函数,链接器为什么只报了3个错误?回答是:实例化的惰性导致这种现象。在main.cpp中还没有用上operator[],编译器还没有实例化它的定义。

      解决方法

      认识了问题,就能够解决问题:

      在实例化要素中让编译器看到模板定义。

      用另外的文件来显式地实例化类型,这样链接器就能看到该类型。

      使用export关键字。

      前二种方法通常称为包含模式,第三种方法则称为分离模式。

      第一种方法意味着在使用模板的转换文件中不但要包含模板声明文件,还要包含模板定义文件。在上例中,就是第一个示例,在array.h中用行内函数定义了所有的成员函数。或者在main.cpp文件中也包含进array.cpp文件。这样编译器就能看到模板的声明和定义,并由此生成array<int, 50>实例。这样做的缺点是编译文件会变得很大,显然要降低编译和链接速度。

      第二种方法,通过显式的模板实例化得到类型。最好将所有的显式实例化过程安放在另外的文件中。在本例中,可以创建一个新文件templateinstantiations.cpp:

      // templateinstantiations.cpp

      #include "array.cpp"

      template class array <int, 50>; // 显式实例化

      array<int, 50>类型不是在main.cpp中产生,而是在templateinstantiations.cpp中产生。这样链接器就能够找到它的定义。用这种方法,不会产生巨大的头文件,加快编译速度。而且头文件本身也显得更加“干净”和更具有可读性。但这个方法不能得到惰性实例化的好处,即它将显式地生成所有的成员函数。另外还要维护templateinstantiations.cpp文件。

      第三种方法是在模板定义中使用export关键字,剩下的事就让编译器去自行处理了。当我在

      Stroustrup的书中读到export时,感到非常兴奋。但很快就发现VC 6.0不支持它,后来又发现根本没有编译器能够支持这个关键字(第一个支持它的编译器要在2002年底才问世)。自那以后,我阅读了不少关于export的文章,了解到它几乎不能解决用包含模式能够解决的问题。欲知更多的export关键字,建议读读Herb Sutter撰写的文章。

      结论

      要开发模板库,就要知道模板类不是所谓的"原始类型",要用其它的编程思路。本文目的不是要吓唬那些想进行模板编程的程序员。恰恰相反,是要提醒他们避免犯下开始模板编程时都会出现的错误。

    展开全文
  • C++中的类模板定义及实例化

    千次阅读 2019-08-21 13:44:08
    文章目录一、类模板定义及实例化定义一个类模板:类模板实例化二、类模板的成员函数 一、类模板定义及实例化 定义一个类模板: template<class 模板参数表> class 类名{ // 类定义...... }; 其中...

    转载自Out man

    一、类模板定义及实例化

    定义一个类模板:

    template<class 模板参数表>
    
    class 类名{
    
    // 类定义......
    
    };
    

    其中,template是声明类模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个,可以是类型参数,也可以是非类型参数。类型参数由关键字class或typename及其后面的标识符构成。非类型参数由一个普通参数构成,代表模板定义中的一个常量。

    例:

    //type为类型参数,width为非类型参数
    template<class type,int width>
    class Graphics;
    

    注意:

    (1) 如果在全局域中声明了与模板参数同名的变量,则该变量被隐藏掉。

    (2) 模板参数名不能被当作类模板定义中类成员的名字。

    (3) 同一个模板参数名在模板参数表中只能出现一次。

    (4) 在不同的类模板或声明中,模板参数名可以被重复使用。

    typedef string type;
    
    template<class type,int width>
    
    class Graphics
    
    {
    
    type node;//node不是string类型
    
    typedef double type;//错误:成员名不能与模板参数type同名
    
    };
    
    template<class type,class type>//错误:重复使用名为type的参数
    
    class Rect;
    
    template<class type> //参数名”type”在不同模板间可以重复使用
    
    class Round;
    

    (5)在类模板的前向声明和定义中,模板参数的名字可以不同。

    // 所有三个 Image 声明都引用同一个类模板的声明
    
    template <class T> class Image;
    
    template <class U> class Image;
    
    // 模板的真正定义
    
    template <class Type>
    
    class Image { //模板定义中只能引用名字”Type”,不能引用名字”T”和”U” };
    

    (6)类模板参数可以有缺省实参,给参数提供缺省实参的顺序是先右后左。

    template <class type, int size = 1024>
    
    class Image;
    
    template <class type=double, int size >
    
    class Image

    类模板实例化

    Graphics<int> gi;
    

    类模板什么时候会被实例化呢?

    ①当使用了类模板实例的名字,并且上下文环境要求存在类的定义时。

    ②对象类型是一个类模板实例,当对象被定义时。此点被称作类的实例化点。

    ③一个指针或引用指向一个类模板实例,当检查这个指针或引用所指的对象时。

    template<class Type>
    
    class Graphics{};
    
    void f1(Graphics<char>);// 仅是一个函数声明,不需实例化
    
    class Rect 
    
    {
    
      Graphics<double>& rsd;// 声明一个类模板引用,不需实例化
    
      Graphics<int> si;// si是一个Graphics类型的对象,需要实例化类模板
    
    }
    
    int main(){
    
      Graphcis<char>* sc;// 仅声明一个类模板指针,不需实例化
    
      f1(*sc);//需要实例化,因为传递给函数f1的是一个Graphics<int>对象。
    
      int iobj=sizeof(Graphics<string>);//需要实例化,因为sizeof会计算Graphics<string>对象的大小,为了计算大小,编译器必须根据类模板定义产生该类型。
    
    }
    

    二、类模板的成员函数

    要点:

    ①类模板的成员函数可以在类模板的定义中定义(inline函数),也可以在类模板定义之外定义(此时成员函数定义前面必须加上template及模板参数)。

    ②类模板成员函数本身也是一个模板,类模板被实例化时它并不自动被实例化,只有当它被调用或取地址,才被实例化。

    template<class type>
    
    Class Graphics{
    
    Graphics(){}//成员函数定义在类模板的定义中
    
    void out();
    
    };
    
    template<class type>//成员函数定义在类模板定义之外
    
    void Graphics<type>::out(){}
    
    展开全文
  • C++模板实例化

    2020-05-27 10:53:43
    文章目录模板实例化C ++有隐式模板实例化和显式实例1. 上面这种方法叫做隐式实例化2.显示实例化 模板实例化 作为C++模板入门修行者,常常会碰到许多问题。其中一项让我们匪夷所思的就是,日常我们习惯将的定义...

    模板实例化

    • 作为C++模板类入门修行者,常常会碰到许多问题。其中一项让我们匪夷所思的就是,日常我们习惯将类的定义和声明拆开来写,分别放置在".h"和".cpp"文件中。
    • 这样做的好处包括但不限于让代码更加清晰,还能够避免重定义的问题,当然如果有双向依赖关系的头文件,或许还要用到诸如前向声明语句。
    • 按照这个思路,将模板分为".h"文件和".cpp"文件,我出现了链接器错误问题LNK2019,寻找博客等,对此的通常答案是将所有模板内容放入".h"文件中,因为必须以这种方式完成。这固然是一种思路,因为编译器能够直接从.h中直接进行模板实例化,而不必去由cpp生成的obj文件中寻找相关定义,再搜寻是否有相应的实例,避免了连接器错误。

    C ++有隐式模板实例化和显式实例

    1. 上面这种方法叫做隐式实例化

    话不多说,我们上代码:

    template.h

    template <typename T>
    class myTemplate
    {
      private:
      T data;
     
      public:
      myTemplate();
      myTemplate(T t);
      T getData() const;
      void displayData() const;
      
      static int someValue; 
    };
      
    template<typename T>
    myTemplate<T>::myTemplate()
    :data()
    {
    }
    
    template<typename T>
    myTemplate<T>::myTemplate(T t) 
    :data(t)
    {
    }
    
    template <typename T>
    T myTemplate<T>::getData() const
    {
        return data;
    }
    
    template <typename T>
    void myTemplate<T>::displayData() const
    {
        std::cout << data <<std::endl;
    }
    
    
    template<typename T>
    int myTemplate<T>::someValue = 100;
    

    main.cpp

    int main()
    {
        myTemplate<int> myTi(5);  
        myTi.displayData();
        
        myTemplate<float> myTf(3.5f);
        myTf.displayData();
          
        return 0;
    }
    
    • 在上面的示例中,完整的模板定义位于main.cpp所包含的头文件中,因此在编译和链接期间没有问题。如果我们忘记对displayData()函数进行定义,那么我们将出现LINK错误,而不是COMPILER错误。

    2.显示实例化

    • 如果想在头文件和源文件之间拆分我们的模板类。即存在template.h和template.cpp。
    • 如果我们编译了这两个文件,但是会收到Linker错误,因为没有实例化template.cpp 文件中的实际代码。
    • 为了使编译器实例化所需的代码,我们可以使用显式实例化。下面上代码:

    template.h

    template <typename T>
    class myTemplate
    {
      private:
      T data;
     
      
      public:
      myTemplate();
      myTemplate(T t);
      T getData() const;
      void displayData() const;
      
      static int someValue;
      
    };
    

    template.cpp

    // 定义复制粘贴,加入下面两行
    template class myTemplate<int>; 
    template class myTemplate<float>;
    
    • 重要的部分是template.cpp中的最后两行。我们知道我们将需要myTemplate 和myTemplate ,因此我们明确要求编译器为这两种类类型的所有可实例化部分生成代码。
    • 这样一来,我们可以成功编译并链接我们的代码了。
    • 此外,我们还可以显式实例化模板函数或单个模板类成员函数。

    代码下载链接

    https://download.csdn.net/download/qq_43055030/12465015

    展开全文
  • C++ 模板的声明与实现分离问题(模板实例化

    万次阅读 多人点赞 2018-10-25 11:11:03
    的),头文件不能与cpp文件分离。这就意味者,你头文件定义的含模版的地方必须在头文件中实现,没用模版定义的地方可以放在cpp中实现。 否则,将产生错误信息: 严重性 代码 说明 项目 文件 行 禁止显示状态 ...

    c++在写模版函数时(template<class T>之类的),头文件不能与cpp文件分离。这就意味者,你头文件定义的含模版的地方必须在头文件中实现,没用模版定义的地方可以放在cpp中实现。

    否则,将产生错误信息:

    严重性 代码 说明 项目 文件 行 禁止显示状态 错误 LNK2019 无法解析的外部符号 "public: void __thiscall XXX

    有什么办法可以是西安模板类的声明与实现分离(模板实例化)问题吗?

     

    模板实例化有什么好处?

    1. 减少编译时间。
    2. 使得类定义与实现分离。

    减少编译时间

    一般来说,如果你的项目没有混合使用 C 和 C++ 语言,那么你使用 .h 和 .cpp 是没有问题的。否则你将C和C++的头文件进行分离,因为通常我们把C和C++分离编译,再统一链接。

    • 函数经过编译系统的翻译成汇编,函数名对应着汇编标号。 因为C编译函数名与得到的汇编代号基本一样,如:fun()=>_fun, main=>_main ;但是C++中函数名与得到的汇编代号有比较大的差别。 如:由于函数重载,函数名一样,但汇编代号绝对不能一样。
    • 为了区分,编译器会把函数名和参数类型合在一起作为汇编代号, 这样就解决了重载问题。具体如何把函数名和参数类型合在一起, 要看编译器的帮助说明了。
    • 这样一来,如果C++调用C,如fun(),则调用名就不是C的翻译结果_fun, 而是带有参数信息的一个名字,因此就不能调用到fun(),为了解决 这个问题,加上extern "C"表示该函数的调用规则是C的规则,则调用 时就不使用C++规则的带有参数信息的名字,而是_fun,从而达到调用 C函数的目的。
    //header.hpp
    
    #pragma once
    
    extern "C"
    {
    #include "header.h" // 真正的 C header
    }

    好的,说会正事 ~

    //foo.hpp (.h和.hpp就如同.c和.cpp似的)
    
    template<typename T>
    struct Foo {
        void f();
    };
    
    //foo.cpp
    
    template<typename T>
    void Foo<T>::f() {}
    
    template class Foo<T1>;
    template class Foo<T2>;

    在标头中声明实例化:

    extern template class A<int>;

    并在一个源文件中定义它:

    template class A<int>;

    现在它只会被实例化一次,而不是每个翻译单元,这可能会加快速度。

    首先需要知道的是把模版类的定义和实现分开写了,编译将会出错。

    C++中每一个对象所占用的空间大小,是在编译的时候就确定的,在模板类没有真正的被使用之前,编译器是无法知道,模板类中使用模板类型的对象的所占用的空间的大小的。只有模板被真正使用的时候,编译器才知道,模板套用的是什么类型,应该分配多少空间。这也就是模板类为什么只是称之为模板,而不是泛型的缘故。

    既然是在编译的时候,根据套用的不同类型进行编译,那么,套用不同类型的模板类实际上就是两个不同的类型,也就是说,stack<int>和stack<char>是两个不同的数据类型,他们共同的成员函数也不是同一个函数,只不过具有相似的功能罢了。

    如上图所示,很简短的六行代码,用的是STL里面的stack,stack<int>和stack<char>的默认构造函数和push函数的入口地址是不一样的,而不同的stack<int>对象相同的函数入口地址是一样的,这个也反映了模板类在套用不同类型以后,会被编译出不同代码的现象。

    所以模板类的实现,脱离具体的使用,是无法单独的编译的;把声明和实现分开的做法也是不可取的,必须把实现全部写在头文件里面。为了清晰,实现可以不写在class后面的花括号里面,可以写在class的外面。

     

    实现分离

    显式实例化允许您创建模板化类或函数的实例化,而无需在代码中实际使用它。因为在创建使用模板进行分发的库(.lib)文件时这很有用,所以未将实例化的模板定义放入对象(.obj)文件中。

    (例如,libstdc ++包含std::basic_string<char,char_traits<char>,allocator<char> >(是std::string)的显式实例化,所以每次使用函数时std::string,都不需要将相同的函数代码复制到对象。编译器只需要将它们引用(链接)到libstdc ++。)

     

    显示实例化时,当你是只有一个 cpp 的情况.可能没有什么问题。但 如果有多个 cpp 文件再使用这个模版, 你必须把它放在头文件里, 然后每个 cpp 都要 #include 这个头文件. 显示实例化之后头文件里只需要声明, 然后在其中一个 cpp 里面实现并显示实例化, 其它的 cpp 就可以直接用了.
     

    在 C++ 中定义普通的类的时候,比较清晰和普遍的做法是在 .h 文件中声明类的接口,如果有 inline 函数也一并放在 .h 中的 class 关键字中。然后在 .cpp 文件中实现 .h 中声明的接口。
    在定义模板类时,如果要将接口与实现分离会略有不同。如果把模板类的实现像普通类一样放在 .cpp 文件中链接器会报错。
    有两个方法可以实现模板类的接口和实现在文件中的分离:

    一个前提

    “类模板的成员函数是一个普通函数。但是类模板的每个实例都有其自己版本的成员函数。因此类模板的成员函数具有和模板相同的模板参数。因此定义在类模板之外的成员函数就必须以关键字 template 开始,后接类模板参数列表。”
    ——《C++ Primer》中文版,第五版,P585

    使用 .tpp 文件实现类模板的接口与实现的文件分离

    比如说有这样一个模板类,这是它的接口:

    template <typename Node>
    class TestTemplate{
    public:
    
      TestTemplate(Node node):
      data(node) { }
    
      Node data;
    
      void print();
    };

    这是它的实现:

    template <typename node>
    void TestTemplate<node>::print(){
        std::cout << "TestTemplate " << data << std::endl;
    }
    

    如果把它们分别放在 .h 和 .cpp 文件中,链接器会报错,提示找不到实现。

    在 .h 文件中模板类的实现下加这一句:

    #include "TestTemplate.tpp"
    

    然后把实现放在名为 TestTemplate.tpp 文件中,即可。

    使用显式声明实现类模板的接口与实现的文件分离

    假设上面那个类的接口与实现分别放在了 .h 和 .cpp 文件中。然后在 .cpp 文件中显式的声明要使用的模板类实例,比如:

    template class TestTemplate<int>;
    

    然后,使用 TestTemplate<int> 也可以通过编译链接,但是只能使用已经显式声明的模板类实例。比如如果还要使用 TestTemplate<float>,就要这样:

    template class TestTemplate<int>;
    template class TestTemplate<float>;
    

    就是说只能只用已经显式声明过的模板类实例。

     

    如果您定义了一个模板类,您只想使用几个显式类型。

    将模板声明放在头文件中就像普通类一样。

    将模板定义放在源文件中,就像普通类一样。

    然后,在源文件的末尾,显式地仅实例化您想要可用的版本。

     

    我的实验:

    //StringAdapter.h
    
    #pragma once
    #include <iostream>
    #include <cstring>
    using namespace std;
    
    template<typename T>
    class StringAdapter
    {
    public:
    	StringAdapter(T* data);
    	void doAdapterStuff();
    private:
    	T* m_data;
    };
    
    #include "StringAdapter.tpp"
    
    
    // StringAdapter.tpp
    #include "StringAdapter.h"
    
    template<typename T>
    StringAdapter<T>::StringAdapter(T* data) : m_data(data)
    {
    	cout << m_data << endl;
    }
    
    template<typename T>
    void StringAdapter<T>::doAdapterStuff()
    {
        /* Manipulate a string */
    	cout << "hello" << endl;
    }
    
    // main.cpp
    #include "StringAdapter.h"
    
    // Note: Main can not see the definition of the template from here (just the declaration)
    //       So it relies on the explicit instantiation to make sure it links.
    int main()
    {
    
    	StringAdapter<const char>  x("hi There");
    	x.doAdapterStuff();
    }
    

     

    stackoverflow 中愚蠢的例子Silly example:

    // StringAdapter.h
    template<typename T>
    class StringAdapter
    {
         public:
             StringAdapter(T* data);
             void doAdapterStuff();
         private:
             std::basic_string<T> m_data;
    };
    typedef StringAdapter<char>    StrAdapter;
    typedef StringAdapter<wchar_t> WStrAdapter;

    source:

    // StringAdapter.cpp
    #include "StringAdapter.h"
    
    template<typename T>
    StringAdapter<T>::StringAdapter(T* data)
        :m_data(data)
    {}
    
    template<typename T>
    void StringAdapter<T>::doAdapterStuff()
    {
        /* Manipulate a string */
    }
    
    // Explicitly instantiate only the classes you want to be defined.
    // In this case I only want the template to work with characters but
    // I want to support both char and wchar_t with the same code.
    template class StringAdapter<char>;
    template class StringAdapter<wchar_t>;

    Main:

    #include "StringAdapter.h"
    
    // Note: Main can not see the definition of the template from here (just the declaration)
    //       So it relies on the explicit instantiation to make sure it links.
    int main()
    {
      StrAdapter  x("hi There");
      x.doAdapterStuff();
    }

     

    一些有趣的小知识

    《C++ Template》第六章讲过这个问题
    组织模板代码有三种方式
    1.包含模型(常规写法 将实现写在头文件中)
    2.显式实例化(实现写在cpp文件中,使用template class语法进行显式实例化)
    3.分离模型(使用C++ export关键字声明导出)

    第三种方式理论最优,但是实际从C++标准提出之后主流编译器没有支持过,并且在最新的C++11标准中已经废除此特性,export关键字保留待用。
    那么实际上能够使用的实现分离也就只有显式实例化

    比较有意思的是,《C++ Template》书中作者建议代码为分离模型做准备,等待编译器支持之后替换,没想到最终这个特性被C++标准废弃了。

    参考:https://www.zhihu.com/question/20630104

               https://bbs.csdn.net/topics/380250382

              http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file

              https://stackoverflow.com/questions/2351148/explicit-instantiation-when-is-it-used

              google搜索:Explicit template instantiation benefits

     

    展开全文
  • [C++]类模板在何时实例化

    千次阅读 2015-12-11 16:40:03
    影响中的一道笔试题,总结了下模板类只声明未定义时,在哪些情况会出现编译错误。... 定义中直接使用类模板的实例模板类而非引用,则在编译时就会对其实例化,因为本例中该类模板只有声明没有定义,所以
  • C++模板实例化与调用

    万次阅读 2015-10-29 13:13:41
    对于函数模板而言,模板实例化之后,会生成一个真正的函数。而类模板经过实例化之后,只是完成了类的定义,模板类的成员函数需要到调用时才会被初始化。模板的实例化分为隐式实例化和显示实例化。
  • 文件操作,数据压缩,文件传输 Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java...
  • 模板的显示实例化与显示具体化

    千次阅读 2019-03-11 19:36:11
    C++中模板函数()的调用与定义分离时,需要使用显式实例化,否则就会出现链接错误。 编译器对各个cpp分别编译的时候,模板函数必须被实例化编译。如果我们把调用与定义写在一个文件,在调用语句处有int a, b; ...
  • 一、类模板定义及实例化 1. 定义一个类模板: 1 templateclass 模板参数表> 2 3 class 类名{ 4 5 // 类定义...... 6 7 };   其中,template 是声明类模板的关键字,表示声明一个模板,模板...
  • 对于函数模板而言,模板实例化之后,会生成一个真正的函数。而类模板经过实例化之后,只是完成了类的定义,模板类的成员函数需要到调用时才会被初始化。模板的实例化分为隐式实例化和显示实例化。 对函数模板的...
  • 对于函数模板而言,模板实例化之后,会生成一个真正的函数。而类模板经过实例化之后,只是完成了类的定义,模板类的成员函数需要到调用时才会被初始化。模板的实例化分为隐式实例化和显示实例化。1.隐式实例化1.1...
  • 模板编译与实例化浅析

    千次阅读 2015-11-12 22:36:34
    编译整体过程(针对C/C++), 1. 预处理:包含宏替换,条件编译,include导入文件 2. 编译: 包含词法分析,语法分析,语义分析,中间代码生成与优化,生成汇编...当编译器遇到一个模板定义时,它并不生成代码。只
  • 编译器用模板产生指定的或者函数的特定类型版本,产生模板特定类型的过程称为函数模板实例化。  编译器用推断出的模板参数来为我们实例化一个特定版本的函数。  当编译器实例化一个模板时,它使用实际的...
  • python的定义与实例化

    千次阅读 2020-11-03 22:42:48
    的定义与实例化 在Python中,通过class关键字定义一个,比如我们需要定义一个人的。按照 Python 的编程习惯,类名以大写字母开头。因此可以这样定义: class Person: pass 注意,在这个Person的定义里面,...
  • Java基础知识面试题(2020最新版)

    万次阅读 多人点赞 2020-02-19 12:11:27
    内部的分类有哪些 静态内部 成员内部 局部内部 匿名内部 内部的优点 内部有哪些应用场景 局部内部和匿名内部访问局部变量的时候,为什么变量必须要加上final? 内部相关,看程序说出运行结果 ...
  • 学习C++模板---模板类作为基类 使用模板类作为基类使用。 // 模板类-晋升.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <process.h> #include <...
  • 什么是类模板? 一个类模板(也称为类属类或类生成类)允许用户为类定义一种模式,使得类中的某些数据成员、默写成员函数的参数、某些成员函数的返回值,能够取任意类型(包括系统预定义的和用户自定义的)。 如果...
  • 1.在编写C++程序时,很多情况下会同时使用函数模板和函数模板的显示具体: void Swap(T &amp;a, T &amp;b) { T temp; temp = a; a = b; b = temp; } template &lt;&gt; void Swap&lt;...
  • 今天在看某c++框架源码时,发现模板类里的部分函数可以特例,感觉很神奇便尝试了下,发现很多平时不会注意的c++细节及知识,写下来分享给大家,以便大家遇到相似问题时可以少踩点坑。 模板类会出现链接问题,编译...
  • C++ 模板何时被实例化

    2013-11-13 00:24:00
    今天编程时碰到一个问题,写了一个单例的类模板,之前程序一直能跑,但今天使用了其中一个函数时却报错。后续查错,发现是自己忘记写结束符号了。 这就引出我知识点的不足了——之前为啥能跑正常?错误一只存在,为...
  • 为了在类模板实例创建时自动调用此静态内部类的构造函数,销毁时自动调用此静态内部类的析构函数 }; template <typename T> T* Singleton<T>::m_pInstance = NULL; // 这句编译通过 template <typename T> ...
  • 在main函数里实例化的时候,就提示了一堆错误了。 ![![图片说明](https://img-ask.csdn.net/upload/201606/18/1466217490_658404.png![图片说明](https://img-ask.csdn.net/upload/201606/18/1466217543_147803.png)...
  • 根据标准,类模板的隐式实例化只会促成static数据成员声明的实例化,不会促成其定义的实例化, 所以rc静态变量的定义没有执行,这个需要我们手动进行定义的实例化。不过这个也不难,只要手动引用一下rc,促进其定义...
  • 首先写了一个包含4个纯虚函数的抽象list,之后派生了一个派生seqList,里面的4个虚函数都重新定义过了,下面是代码(template说明是模板类,不用管;有的函数只是声明一下,实现就没有列出来) template ...
  • 模板
  • 工作积累之模板类实例化

    千次阅读 2012-03-14 09:57:38
    模板函数在声明的时候, 其实并不存在,函数地址也就无从谈起了,而导出到动态链接库的函数都需要有地址 (动态链接库不能将模板类导出,因为没法生成实例) ...原因是模板类实例化要分成两个步骤,模板的特例化
  • C++ 函数模板&类模板详解

    千次阅读 2018-12-02 16:32:37
    在 C++ 中,模板分为函数模板和类模板两种。函数模板是用于生成函数的,类模板则是用于生成类的。...由类模板实例化得到的类叫模板类   一.函数模板 函数模板的基本写法为:template &lt;typ...
  • 模板分为模板函数和模板类。 如果是交换两个数据,我们会定义对应类型的函数,比如要交换int类型数据,我们会定义int类型swap函数,如果是交换double类型数据,会再定义double类型交换函数。 void Swap(int&...
  • JAVA上百实例源码以及开源项目

    千次下载 热门讨论 2016-01-03 17:37:40
     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...
  • C++函数模板与类模板的区别

    万次阅读 多人点赞 2018-07-18 16:54:55
    类模板: C++ 除了支持函数模板,还支持类模板...类模板的目的同样是将数据的类型参数。 声明类模板的语法为: template&lt;typename 类型参数1 , typename 类型参数2 , …&gt; class 类名{  //TODO: }...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 116,625
精华内容 46,650
关键字:

关于类模板的实例化错误的是