精华内容
下载资源
问答
  • C++模板类声明和定义几种写法

    万次阅读 2018-11-29 01:01:17
    为什么模板类的实现放在cpp会出错 在编译用到了模板类的编译单元时,编译器需要访问方法或者的实现...声明和定义都放在.h中 // Foo.h template <typename T> struct Foo { ...

    为什么模板类的实现放在cpp会出错

    在编译用到了模板类的编译单元时,编译器需要访问方法或者类的实现,以实例化它们。 如果这些实现不在头文件中,则它们将不可访问,因此编译器将无法实例化模板,进而会导致编译出错。

    模板类的定义必须放在.h文件中吗

    答案是否定的,模板类的几种写法

    声明和定义都放在.h中

    // Foo.h
    template <typename T>
    struct Foo
    {
        void doSomething(T param) {}
    };
    

    声明和定义分隔开

    // Foo.h
    template <typename T>
    struct Foo
    {
        void doSomething(T param);
    };
    
    #include "Foo.tpp"
    
    // Foo.tpp
    template <typename T>
    void Foo<T>::doSomething(T param)
    {
        //implementation
    }
    

    实现放在了Foo.tpp,然而还是include Foo.tpp在了头文件中,只是做了文件的分隔,但是其他文件include了头文件后,还是把实现也包含进去了,跟都放在.h效果类似,只是实现和声明分开,代码可读性更好

    声明放在.h文件,定义放在.cpp文件

    // Foo.h
    // no implementation
    template <typename T> struct Foo { ... };
    
    //----------------------------------------    
    
    // Foo.cpp
    // implementation of Foo's methods
    
    // explicit instantiations
    template class Foo<int>;
    template class Foo<float>;
    // You will only be able to use Foo with int or float
    

    正在的声明和实现分离,include了头文件之后不会把实现的代码也加入到该编译单元。然后需要将所有用到的类型都显式的实例化

    什么是实例化

    编译器怎么处理模板呢?本质上来说,模板可被编译器产生多种多样函数和类的代码。只有当被使用的时候,编译器才会产生用于这种类型的代码。模板不是直接编译成以后需要的各种类的实现,而是将模板代码解析放入内存中,当编译某个编译单元需要用到该模板,则会按需产生相应的代码。实例化是编译器确定特定模板与特定参数集一起使用并在模板上执行参数替换以生成要编译的类或函数以及最终编译为模板的二进制代码的过程。

    有两种类型模板实例化,隐式和显式。
    显式的实例化见第三段代码,Foo.cpp中显式实例化了Foo和Foo。显式实例化会实例化所有的成员函数。
    隐式实例化是一种按需实例化。当你使用一个模板类时,编译器才会进行实例化。例如如果你使用vector,此时编译器才会创建一个vector类型,并且只会实例化所需要的函数。不实例化所有的成员函数主要有两点原因:
    1、节省编译时间
    2、不同的成员函数对类型属性有一些要求,不实例化可以使得更多的类型可以用到模板类。例如map的operator[]操作符要求value是有默认构造函数的,因为你通过不存在的key访问value的时候会新建一个value,且是需要调用默认构造函数。如果你不需要这个操作,用find和insert也可以达到目标,这样对value的类型就少了一个限制,使得模板类更具有普适性。

    特化template时遇到的duplicate symbol问题

    stackoverflow上面有案例,详见multiple definition of template specialization when using different objects

    Intuitively, when you fully specialize something, it doesn’t depend on a template parameter any more – so unless you make the specialization inline, you need to put it in a .cpp file instead of a .h or you end up violating the one definition rule as David says. Note that when you partially specialize templates, the partial specializations do still depend on one or more template parameters, so they still go in a .h file.

    翻译过来:
    直观地说,当你完全特化某些东西时,它不再依赖于模板参数,所以除非你使内联专业化,你需要将它放在.cpp文件中而不是.h中,否则你最终会违反大卫说的一个定义规则。 请注意,当您对模板进行部分特化时,部分特化仍然依赖于一个或多个模板参数,因此它们仍然位于.h文件中。
    推荐的写法为:
    举例,template中static成员的初始化,完全特化实现在.cpp中

    template<> int B<A, 1>::a[1] = { };
    

    声明在.h中

    template<> int B<A, 1>::a[1];
    

    详见static member initialization for specialized template class

    参考文档

    Why can templates only be implemented in the header file?
    Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
    c++ 模板类 声明和定义都放在.h文件的原因
    Meaning of ‘instantiation’ with respect to templates

    展开全文
  • c++模板类声明和定义的问题

    千次阅读 2019-08-18 21:38:39
    这里在学习的过程中遇到的一些问题,比较简单,但还是记下来,以免下次遇到这个问题再犯,大佬们可跳过哦。先简单的介绍下模板的概念 C++模板(泛型编程) c++模板是泛型编程的基础,所谓...模板和类模板的概念 一个...

    这里在学习的过程中遇到的一些问题,比较简单,但还是记下来,以免下次遇到这个问题再犯,大佬们可跳过哦。先简单的介绍下模板的概念

    C++模板(泛型编程)

    c++模板是泛型编程的基础,所谓泛型编程也是一种思想,一种抽象数据类型,但是泛型是不属于面向对象,它是面向对象的补充和发展。使用泛型编程简单来说就是能让你把一些相同的代码用指定的去替换它,算是程序员找到的一个偷懒的方法吧。

    模板类和类模板的概念

    一个类模板(类生成类)允许用户为类定义个一种模式,使得类中的某些数据成员、默认成员函数的参数,某些成员函数的返回值,能够取任意类型(包括系统预定义的和用户自定义的)。

    如果一个类中的数据成员的数据类型不能确定,或者是某个成员函数的参数或返回值的类型不能确定,就必须将此类声明为模板,它的存在不是代表一个具体的、实际的类,而是代表一类类。

    类模板定义格式:

    template<typename T>    //这里的typename也可写成class,是一样的,class是之前程序员们所写的一种方式
    class Test
    {
    private:
    	T n;
    	const T i;
    public:
    	Test():i(0){}
    	Test(T k);
    	~Test(){}
    public:
    	void print();
    	T operator+(T x);
    }
    

    如果是在类外定义成员函数,且这个成员函数中有模板参数存在,那么除了和一般类的类外定义成员函数一样定义,还需要在函数外进行模板声明
    例:

    template<typename T>
    void Test<T>::print()
    {
    	cout<<"n="<<n<<endl;   //这里在上面已经添加了iostream
    	cout<<"i="<<i<<endl;
    }
    
    template<typename T>
    Test<T>::Test(T k):i(k)    //这里是初始化列表
    :i(k)
    {
    		n = k;
    }
    template<typename T>
    T Test<T>::operator+(T x)
    {
    	return n+x;
    }
    

    好了,概念抛个差不多就行了,现在开始抛问题,上图
    这种问题呢对于小白来说应该是比较容易犯的一个错误,当你看见语法错误,缺少分号的时候,你肯定会到编辑器报的错误的地方认真仔细的看一遍(这里假想情况是模板类声明和实现分开写的),没毛病呀,于是又仔细的看一遍,还是找不到错误的地方。好了,这种情况实际上是因为前面写类的时候后面忘了添加分号的原因哦,所以请到.h文件中查看类的后面是不是少写了一个分号吧。
    对于这种出现大量函数模板已经定义的情况,很大情况是由于头文件冲突所导致的,如果你是.h和.cpp分开写的话,可以在.h的类后面加上#include xxx.cpp,其中的内容是你写的类名,这种写法呢其实就相当于把声明和实现写在了一个文件里。这里要注意在.cpp文件里面不要包含当前类的.h文件哦,不要包含,不要包含,不要包含!当然你还有可能出现命名冲突的情况,那么你可以在.h文件中头部添加#infdef XXXX_H,#define XXXX_H,这里写你的文件名,然后尾部再写上#endif。如果你遇到了非常糟糕的情况:error LNK2019:无法解析的外部符号的情况,后面跟着名称粉碎,那还是再看看头文件吧。

    好了,说的这些应该是非常基础的一些知识了,好吧,对于大佬来说肯定会有鄙视的眼神的,这些都是常识。唔,好吧,大佬说的都是对的。第一次写博客,写的非常的简陋,今后有时间的话争取把内容再扩充扩充吧。

    展开全文
  • c++中模板_类模板声明和定义

    千次阅读 2017-11-17 11:24:18
    就行,其余正常定义和申明 Ø 调用时,跟正常函数一样调用 注意: Ø 模板在调用时,才确定参数的具体类型!!! Ø 模板声明或定义只能在全局,命名空间或范围内进行。即不能在局部范围,函数内进行,比如...

    一、函数模板用法

    1.1申明和定义

    Ø  在函数申明和定义前面,加一个模板template<classT, classC>就行,其余正常定义和申明

    Ø  调用时,跟正常函数一样调用

    注意:

    Ø  模板在调用时,才确定参数的具体类型!!!

    Ø  模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板

    1.2调用示例

    template<classT, classC> T add1(T, T, C);
    
    int main()
    
    {
    
        add1(1, 2, 3); //只用到模板T,没有用到模板C
    
        add1(1.5, 3.5, 3); //只用到模板T,没有用到模板C
    
        return NULL;
    
    }
    
    
    
    template<classT, classC> T add1(T a, T b,C c)
    
    {
    
       return a + b; //只用到模板T,没有用到模板C
    
    }

    二、类模板用法

    2.1类模板的声明和定义

    2.1.1类模板的申明

    Ø  在类前面加一个模板template<classT, classC>就行

    2.1.2类模板的定义

    Ø  在类在类前面加一个模板template<classT, classC>

    Ø  在定义类后加<T,C>。比如类A的函数Add,定义为void A<int>::Add(T a, T b)

    2.1.3类模板调用

    将在定义类后加<T,C>改为<int,double>

    比如示例一个对象a:

    A<int> a;

     

    2.2具体示例

    *.h申明

    template<classT> classA//类模板声明,类前面加template<class T>
    
    {
    
    public:
    
       T a1;
    
       int Add1(T t1,T t2);
    
    };

    *.cpp定义

    //类模板声明,类前面加template<class T>。并且类A后面带这个<T>
    
    template<classT> intA<T>::Add1(Tt1, T t2)
    
    {
    
       return t1 +t2;
    
    }

    成员函数调用

    A<int> a;//实例化一个类,A后面带这个A<int>
    
    int aa =a.Add1(2, 3);//调用模板成员函数,跟模板函数一样调用就行

    三、模板类默认值设置

    3.1模板类的形参为类型形参

    Ø  类模板可以设置默认值,函数模板不能设置默认值

    Ø  设置默认值时,尽量放在最后,不要放在开头

    Ø  如果放在开头,后面一定要设置默认值,并且跟第一个默认值一样

    例如:

    template<classT1 = int,class T2 =int> class CeilDemo{…}

     

    3.2示例

    TemplateDemo03.h

     

    #ifndefTEMPLATE_DEMO_03
    #define TEMPLATE_DEMO_03
    
    //定义带默认类型形参的类模板。这里把T2默认设置为int型
    template<classT1, classT2 = int>class CeilDemo{
    public:
       int ceil(T1,T2);
    };
    
    //在类模板的外部定义类中的成员时template后的形参表应省略默认的形参类型
    template<classT1, classT2>
    int CeilDemo<T1,T2>::ceil(T1a, T2 b){
       return a>> b;
    }
    
    #endif

    TemplateDemo03.cpp

    #include<iostream.h>
    #include "TemplateDemo03.h"
    
    void main(){
       CeilDemo<int> cd;
       cout <<cd.ceil(8, 2) << endl;
    }

     

     

    参考内容:

    http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html

    http://blog.csdn.net/zhongshan_c/article/details/8917470

    http://blog.csdn.net/elcoteq983/article/details/7032213

    展开全文
  • 为什么 c++中函数模板和类模板声明定义需要放到一起? 一般来说,模板声明定义,都放在同一个头文件里,其它cpp需要用的时候包这个头文件。 但是,将模板声明定义写在一起实在很不优雅。尝试用...

    为什么 c++中函数模板和类模板的 声明与定义需要放到一起?

    一般来说,模板的声明和定义,都放在同一个头文件里,其它cpp需要用的时候包这个头文件。

     

    但是,将模板的声明与定义写在一起实在很不优雅。尝试用“传统”方法,及在.h文件里声明,在.cpp文件里定义,

    然后在main函数里包含.h头文件,这样会报链接错误。

    这是因为函数模板要被实例化后才能成为真正的函数,在使用函数模板的源文件中包含函数模板的头文件,(carefully!!!)

    如果该头文件中只有声明,没有定义,那编译器无法实例化该模板,最终导致链接错误。(类模板同样!!)

    //---------------test.h-------------------// 
    void f();//这里声明一个函数f 
    
    
    //---------------test.cpp--------------// 
    #include”test.h” 
    void f() 
    { 
     …//do something 
    } //这里实现出test.h中声明的f函数 
    
    
    //---------------main.cpp--------------// 
    #include”test.h” 
    int main() 
    { 
        f(); //调用f
    }

    编译时会生成两个obj文件,main.obj和test.obj,而在main.obj里并没有f函数的二进制代码,这些代码实际存在于test.obj中。

    在main.obj中对 f 的调用只会生成一行call指令,call指令的地址由链接器生成。

     

    我们知道模板有个具现化的过程,在未被使用的时候是不会生成二进制文件的。所以当链接器去找f函数的地址时,因为在这之前没有调用过f(),test.obj里自然就没有f函数的二进制代码,于是就会报错。

    //-------------test.h----------------// 
    template<class T> 
    class A 
    { 
      public: 
        void f(); //这里只是个声明 
    };
     
    //---------------test.cpp-------------// 
    #include”test.h” 
    template<class T> 
    void A<T>::f() 
    { 
    …//do something 
    } 
    
    //---------------main.cpp---------------// 
    #include”test.h” 
    int main() 
    { 
        A<int> a; 
        a.f(); 
    }

     

    要使模板声明与定义分开也不是没有办法。

    第1种办法是在main函数里包含实现了模板定义的文件

    //-------------test.h----------------// 
    template<class T> 
    class A 
    { 
      public: 
        void f(); //这里只是个声明 
    }; 
    
    //---------------test.cpp-------------// 
    #include”test.h” 
    template<class T> 
    void A<T>::f() 
    { 
    …//do something 
    }
     
    //---------------main.cpp---------------// 
    #include”test.cpp” //careful!!!!!!!!!
    int main() 
    { 
        A<int> a; 
        a.f(); 
    }

    这样三个文件的内容通过include实际上包含在同一个文件里,自然就不会出错了

     

    第2种办法是,在模板定义文件的末尾,重新声明具现的函数模板(类模板)类型

    //-------------test.h----------------// 
    template<class T> 
    class A 
    { 
      public: 
        void f(); //这里只是个声明 
    }; 
    
    /---------------test.cpp-------------// 
    #include”test.h” 
    template<class T> 
    void A<T>::f() 
    { 
    …//do something 
    } 
    template class A<int>;//在这里实现了具现的类型  这样编译就不会有问题了  但是这样不太好
    /---------------main.cpp---------------// 
    #include”test.h” 
    int main() 
    { 
        A<int> a; 
        a.f(); 
    }

     

    展开全文
  • “通常情况下,你会在.h文件中声明函数和类,而将它们的定义放置在一个单独的.cpp文件中。但是在使用模板时,这种习惯性做法将变得不再有用,因为当实例化一个模板时,编译器必须看到模板确切的定义,而不仅仅是它的...
  • 习惯性的将函数的定义和实现,分别写在头文件和源文件(.cpp)中。今天也按照这个习惯实现了一个模板函数。然后编译时报错 ... error: undefined reference to ... 2、原因分析 c++中模板声明和定义不能分开。C++...
  • 在《C++ primer》教材中,将模板声明和定义分别放在头文件(.h)(.cpp)中的模板编译模型分为两种,一种是包含编译模型(inclusion compilation model),另一种是分别编译模型(separate compilati...
  • c++模板函数声明和定义分离

    千次阅读 2016-09-24 12:32:39
    c++模板不支持分离编译, 把你模板类声明和实现放到.h文件里面 。按照这个说的把.h.cpp文件合并后,果然可以了。 但是为什么呢,为什么模板就不支持分离编译?---继续google ing 搜到了如下文章(文章原文...
  • 模板类声明和定义为何要写一起

    千次阅读 2016-10-09 21:43:07
    如何组织编写模板程序  发表日期: 1/21/2003 12:28:58 PM  发表人: Nemanja Trifunovic ...常遇到询问使用模板到底是否容易的问题,我的回答是:“模板的...看看我们几乎每天都能遇到的模板类吧,如STL, ATL, WT
  • 类模板定义总结

    2019-07-28 11:21:50
    以下个通过一个简单的例子做一说明: template class M{ public: M( m = 0 ):m(m){} ...例子虽然简单但是可以很好的诠释...1.类模板定义对象,必须要指定对象的类型。 2.类模板作为函数参数时,必须指定类型。
  • 模板类声明和定义中分离.h与.cpp

    千次阅读 2012-10-05 22:40:03
    如果你用模板类的时候跟其它一样把声明放在.h中那个,把定义放在.cpp中,是不是也出现了令人恼怒的 无法解析的外部符号 错误,在解决问题之前,请先看一下这篇关于编译原理的介绍,毕竟做学问要知其然更要知其...
  • 看看我们几乎每天都能遇到的模板类吧,如STL, ATL, WTL, 以及Boost的模板类,都能体会到这样的滋味:接口简单,操作复杂。 我在5年前开始使用模板,那时我看到了MFC的容器。直到去年我还没有必要自己编写模板类...
  • 因此,我们将类定义和函数声明放置在头文件中,普通函数和成员函数的定义放置在源文件中。 模板则不同,为了生成一个实例化版本,编译器需要掌握函数模板或者类模板成员函数的定义。 结论: 函数模板和类模板成员函数...
  • 关于C++模板函数声明定义的问题

    万次阅读 多人点赞 2018-07-22 21:59:37
    关于C++模板函数声明定义的问题 关于C++模板函数声明定义的问题 模板函数出现的问题 模板函数问题解决 模板函数出现的问题 今天在写代码的时候,发现了一个关于模板函数的问题。如下所示, demo...
  • “通常情况下,你会在.h文件中声明函数和类,而将它们的定义放置在一个单独的.cpp文件中。但是在使用模板时,这种习惯性做法将变得不再有用,因为当实例化一个模板时,编译器必须看到模板确切的定义,而不仅仅是它的...
  • #include "stdafx.h"  ...//---------------------------------情况1: 类模板中成员模板体内定义方法:-------------------------------------------- template//类模板 class A { public
  • 模板声明和定义 头文件与源文件

    千次阅读 2018-03-22 10:46:47
    今天,写了一个List的模板类,然后把它的声明和定义分别放在头文件和源文件中,发现编译不通。然后,就有疑问了,一是为什么那些普通我们分为头文件和源文件能编译通过,二是模板为什么不行,所以这个编译究竟做了...
  • 今天尝试自己实现vector数据结构底层,在定义vector模板类的时候,还想像往常一样把分为.h文件.cpp文件,把成员函数的声明放在.h文件中,把具体实现放在.cpp文件中,结果在测试时发现在编译过程中报错。...
  • 在看《大化数据结构》的过程中,出现了类模板定义,由于自己c++编写能力并不是很好,自己写了一个类模板,无论怎么写都出现如下错误: 错误 3 error LNK1120: 2 个无法解析的外部命令 F:\leetcode\Sqlist\...
  • 写了3年多C++程序,很少用到模板,我靠,今天想试一下,照着别人的例子写,什么鬼,怎么都运行不过,仔细比对代码才发现,C++模板声明定义必须放到一个文件,.h或者.hpp, 真是颠覆我对C++编程的认知,什么坑爹的...
  • C++类模板声明与实现分离

    千次阅读 2017-05-25 11:39:31
    模板声明与实现分离未处理得当时,会出现链接错误,如下: error LNK2019: unresolved external symbol poisson referenced 其实,LNK2019错误一般都是 compile是能找到相应的header (.h)文件,但链接时找不到...
  • C++类模板类成员的定义方法

    千次阅读 2019-09-05 16:18:23
    举个栗子: template<typename T>//代表这是个类模板 class BinaryTree { public: BinaryTree(); ~BinaryTree();... //类模板内成员定义 } private: }; /*类模板的构造函...
  • 对普通函数来说,声明放在头文件中,定义放在源文件中,其它的地方要使用该函数时,仅需要包含头文件即可,因为编译器编译时是以一个源文件作为单元编译的,当它遇到不在本文件中定义的函数时,若能够找到其声明,则...
  • 前面提到了模板声明和定义推荐都放在头文件中,那么该中的友元函数的声明和定义该放在哪里呢?  因为友元函数并不属于这个, 按照习惯,我们一般把声明放在中,而把定义放在的外面。但对于类模板来说,...
  • 关于模板函数声明定义的问题

    万次阅读 2016-01-08 21:20:37
    c++ primer上说:c++模板函数的声明定义通常放在头文件中,而普通的函数通常是声明放在头文件中,定义放在源文件中,为什么会有这样的区别呢?模板函数与普通成员函数到底有什么区别? 测试代码: tem.h #...
  • C++函数模板声明和定义分离的方法

    千次阅读 2013-12-14 01:48:13
    废话不说,先上代码。 // template_test.h template T MyMax(T a,T b); template float MyMax(float a,float b);... 另外,这种方法只适用于函数模板类模板中成函数还是要声明和实现在同一文件中。
  • c++模板类/模板函数的声明定义应该放在头文件里,不要分开来写中函数的声明定义(比如在.H文件里声明某个成员函数,在.CPP文件里定义该成员函数),这样会导致连接错误。所应该将模板类/模板函数的定义声明...
  • c++ 模板类 声明和定义都放在.h文件的原因

    千次阅读 多人点赞 2014-03-20 00:29:11
    看下面的例子(将模板声明和实现分离): //-------------test.h----------------// template classA { public: voidf(); // 这里只是个声明 }; //---------------test.cpp-------------//...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 226,540
精华内容 90,616
关键字:

类模板的声明和定义