首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

错误使用 C++ 模板特化产生的坑

今天在群里看到了一个错误使用 C++ 模板特化产生的坑,有点意思,这里记录一下。...简单来说,正确的模板特化写法应该是将特化声明写在头文件里,必须在使用该模板之前出现对应声明,否则编译器就会进行自动实例化: // a.h #pragma once #include ...问题虽然就这样解决了,但是刚刚的描述好像有点不对劲。我们说之前错误的写法会导致编译器自动实例化模板,而链接 .o 文件的时候,又会将 .o 中的符号链接进最终结果里,那这个时候怎么就没产生符号冲突呢?...当模板使用前没有声明特化时,编译器不知道这个模板有特化的版本,会实例化一个基础版本(弱符号) 当模板使用前有声明特化时,编译器会去外部查找这个特化版本的定义,而非自己实例化 模板特化声明必须写在头文件中...,在使用之前必须让编译器看到这个特化声明,否则会出问题 模板特化声明必须写在头文件中,在使用之前必须让编译器看到这个特化声明,否则会出问题 模板特化声明必须写在头文件中,在使用之前必须让编译器看到这个特化声明

41930

C++ 模板元编程简介

理论上说 C++ 模板可以执行任何计算任务,但实际上因为模板是编译期计算,其能力受到具体编译器实现的限制(如递归嵌套深度,C++11 要求至少 1024,C++98 要求至少 17)。...模版元程序由元数据和元函数组成,元数据就是元编程可以操作的数据,即C++编译器在编译期可以操作的数据。...4.模板元编程的控制逻辑 第一个 C++ 模板元程序由Erwin Unruh 在 1994 年编写,这个程序计算小于给定数 N 的全部素数(又叫质数),程序并不运行(都不能通过编译),而是让编译器在错误信息中显示结果...(直观展现了是编译期计算结果,C++ 模板元编程不是设计的功能,更像是在戏弄编译器。...与此同时,模板元编程也存一定缺点,主要有: (1)模板元编程产生的代码较为复杂,难易阅读,可读性较差; (2)大量模板的使用,编译时容易导致代码膨胀,提高了编译时间; (3)对于C++来说,由于各编译器的差异

6.9K42
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    C++ 模板沉思录(下)

    花下猫语:在我们读者群里,最近出现了比较多关于 C++ 的讨论,还兴起了一股学习 C++ 的风气。樱雨楼小姐姐对 C++ 的模板深有研究,系统地梳理成了一篇近 4 万字的文章!...这是由于C++的表达式语义本就是“积极主动的”,当编译器看到lhs + rhs...时,其就必须遵守C++的语义规定,立即计算此加法,而“暂且不顾”后续表达式。...看来,编译器优化是彻底不可能帮得上忙了。这让我们陷入了困境之中。 7.2 一个天马行空的想法 既然编译器帮不上忙,那我们是否能通过某种技术,“绕过”编译器的这种主动计算呢?...——后记 模板,最早于上世纪90年代被引入至C++,此后的多年内,模板技术迅速发展,促使了大量与之相关的程序设计技术的出现与成熟,并直接导致了STL的出现。...正如《Modern C++ Design》一书的中文译序中所言,这些书籍所讲述的技术,使得我们不再认为模板只是一位“戴上了新帽子”的旧朋友。

    1.2K30

    C++箴言:理解typename的两个含义

    相信学习C++的人对class这个关键字都非常明白,class用于定义类,在模板引入c++后,最初定义模板的方法为:       template......      ...c++编译器,typename后面的字符串为一个类型名称,而不是成员函数或者成员变量,这个时候如果前面没有typename,编译器没有任何办法知道T::LengthType是一个类型还是一个成员名称(静态数据成员或者静态函数...但是从 C++ 的观点看,class 和 typename 在声明一个 template parameter(模板参数)时意味着完全相同的东西。   ...作为结束语,我应该提及编译器与编译器之间对围绕 typename 的规则的执行情况的不同。...一些编译器接受必需 typename 时它却缺失的代码;一些编译器接受不许 typename 时它却存在的代码;还有少数的(通常是老旧的)会拒绝 typename 出现在它必需出现的地方。

    4.7K20

    【深入探索 C++ STL 双端队列 deque】 —— 数据时空的双端虫洞,扭曲常规操作的效率边界

    >,deque是 C++ 标准模板库(STL)中的一个容器类,它允许在两端进行高效的插入和删除操作。...2.1、 模板参数(Template Parameters) 模板参数T 表示元素的类型,别名为成员类型deque::value_type 模板参数Alloc 用于定义存储分配模型的分配器对象的类型。...operattor[ ]不会强制检查,如果访问的元素的下标超出deuqe对象的范围,则会导致未定义的错误,不同的编译器的处理方式不同!...不同的编译器对于迭代器失效的检查不同: 【VS下的检查机制:】 Visual Studio(VS)对于代码规范性和潜在错误有着比较严格的检查机制,基于一种保守的策略来防止潜在的错误使用迭代器情况,所以VS...在 C++ 学习的浩瀚星空中,我们都是执着的追光者,每一次成功解析一个晦涩的错误,每一回透彻理解一个精妙的算法,都是我们穿越星际迷雾的胜利。

    21710

    Effective Modern C++翻译(5)-条款4:了解如何观察推导出的类型

    编译器的诊断 知道编译器对某一类型推导出的结果一个有效方法是让它产生一个编译期的错误,因为错误的报告肯定会提到导致错误的类型。...== "Type Displayer" 尝试实例化这个模板会产生一个错误信息,因为没有模板的定义,想要查看x和y的类型只需要用它们的类型实例化TD TD xType; // 引起错误的信息包括了...,我所测试的所有编译器都提供了包括类型的信息的错误诊断信息。...C++ filt工具,来对这些重整后的名字进行解码),理解编译器的输出将变得容易起来,Microsoft的编译器提供了更清楚的输出,x的类型是int,y的类型是int const*....在我的经验中,使用编译器的错误诊断信息来知道变量被推导出的类型是相对可靠的方法,利用修订之后的函数模板f来实例化只是声明的模板TD,修订之后的f看起来像下面这样 template

    72480

    移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——13.map&&set

    4.set (K模型) set使用介绍 set是标准模板库(STL)中的一种关联容器,它存储的元素是唯一的,并且按照特定的顺序(默认是升序)自动排序。...1. set的模板参数列表 T: set中存放元素的类型,实际在底层存储的键值对。...键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类 型value_type绑定在一起,为其取别名称为pair: typedef pair value_type;...在multimap中,通常按照key排序和惟一地标识元素,而映射的value存储与key关联的内 容。...key和value的类型可能不同,通过multimap内部的成员类型value_type组合在一起, value_type是组合key和value的键值对: typedef pair value_type

    6710

    剖析STL源码,明白typename

    查看C++ Primer之后,发现两者完全一样....我们猜测是这样的,现实是不是呢? 可是,如果是像T::iterator这样呢?T是模板中的类型参数,它只有等到模板实例化时才会知道是哪种类型,更不用说内部的iterator。...如果实例化foo模板函数的类型是像这样的: struct MyIterator { static int iterator; }; 那么,T::iterator * iter;被编译器实例化为MyIterator...’ typename 对于用于模板定义的依赖于模板参数的名称,只有在实例化的参数中存在这个类型名,或者这个名称前使用了typename关键字来修饰,编译器才会将该名称当成是类型。...* iter; } 这样编译器就可以确定T::iterator是一个类型,而不再需要等到实例化时期才能确定,因此消除了前面提到的歧义。

    61940

    C++之map和set

    SGI-STL中对于键值对的定义: template struct pair { typedef T1 first_type; typedef T2 second_type...set的使用 set的模板参数列表 Compare 参数是比较器类型,一般不需要显示传递,如果无法比较(自定义类型),需要用户自己显示传递比较规则(一般情况下按照函数指针或者仿函数来传递)。...在map内部,key与value通过成员类型value_type绑定在一起,并取别名为pair; typedef pair value_type; 在map中,元素总是按照键值...map的使用 map的模板参数列表 Compare 参数是比较器类型,一般不需要显示传递(缺省为小于比较,即升序排序),如果无法比较(自定义类型),需要用户自己显示传递比较规则(一般情况下按照函数指针或者仿函数来传递...本文作者目前也是正在学习C++相关的知识,如果文章中的内容有错误或者不严谨的部分,欢迎大家在评论区指出,也欢迎大家在评论区提问、交流。

    75330

    两万字长文,见过最好的模板元编程文章!

    std::cin.get(); return 0; } 所以模板代码写完后最好写个诸如显示实例化的测试代码,更深入一些,可以插入一些模板调用代码使得编译器及时发现错误,而不至于报出无限长的错误信息。...),代码计算是通过类型计算进而选择类型的函数实现的(C++ 属于静态类型语言,编译器对类型的操控能力很强)。...3 编译器数值计算 第一个 C++ 模板元程序是 Erwin Unruh 在 1994 年写的(文献[14]),这个程序计算小于给定数 N 的全部素数(又叫质数),程序并不运行(都不能通过编译),而是让编译器在错误信息中显示结果...(直观展现了是编译期计算结果,C++ 模板元编程不是设计的功能,更像是在戏弄编译器,当然 C++11 有所改变),由于年代久远,原来的程序用现在的编译器已经不能编译了,下面的代码在原来程序基础上稍作了修改...C++ 模板的能力,可以用模板实现类似普通程序中的 if 和 while 语句; 一个实际应用是循环展开,虽然编译器可以自动循环展开,但我们可以让这一切更可控; C++ 模板编程的两个问题是:难调试,会产生冗长且难以阅读的编译错误信息

    1.4K10

    C++中typename的用法

    其形式是:typedef+原类型名+新类型名;因此,我们可以知道typename iterator_traits::value_type是类型名;但是感到困惑的是这里为什么要使用typename...typename的常规用法 typename在C++类模板或者函数模板中经常使用的关键字,此时作用和class相同,只是定义模板参数;在下面的例子中,该函数实现泛型交换数据,即交换两个数据的内容...内使用using std::cout;,然后使用时只用cout和endl,它们的前面不再有空间限定...然而对于接下来的三行定义,只有在模板实例化时才能知道它们的类型,因为它们都依赖于模板参数T。则T, vector, vector::iterator称为依赖名。...编译器可能认为我们是想实现乘法运算;若我们的本意是想定义一个指针时,这是就需要typename来修饰,即在T::iterator前面加上关键字typename;template class

    3.2K30

    C++知识点

    还没有整理过的笔记,有点乱 C++ 程序设计 II 兼谈对象模型 Conversion function - 转换函数 operator type() // this type -> other type...) () 函数调用操作符 function call 一般只要看到 class 内重载了 () 操作符,那他的用意就是想要变成一个 function, 其构造的对象称为函数对象 标准库中,仿函数会继承一些奇特的基类如...Object Model 对象模型 Part I 的承接 Inheritance 继承:构造由内而外,析构由外而内 Composition 复合:构造由内而外,析构由外而内 Inheritance...+Composition:构造由内而外,析构由外而内 Derived::Derived(...) : Base(),Component() {...}...n 个虚函数 (*(p->vptr)[n])(p); (* p->vptr[n] )(p); ---- 应用:PPT 图形类(多态的应用) 总结:  C++ 编译器看到一个函数调用,会有两个考量(静态绑定

    88130

    C++:20---类模板(template)

    如果模板类的成员函数在类内声明,而在类外定义,需要遵循以下规则:在函数前也在加上模板列表,且类名限定符后面给出 template class Blob{public:Blob...::size_type //编译器知道我们要访问string类中的size_type数据类型 但是对于模板就不能使用这种方法了,例如: //编译器不知道size_type是一个static数据成员还是一种数据类型...,因此产生二义性T::size_type * p; 默认情况下,C++语言假定通过作用域运算符访问的名字不是数据类型,而是数据成员。...所以如果我们希望使用一个模板类型参数的类型成员,就必须显式地告诉编译器改名字是一个类型。...c.empty()) return c.back(); else return typename T::value_type();} 七、成员模板 一个类可以包含模板类型的成员函数,这种成员称为“成员模板

    1.3K20

    C++一分钟之概念(concepts):C++20的类型约束

    在C++的漫长进化历程中,Concepts(概念)作为C++20引入的一个重大特性,为模板编程带来了革命性的变化。...忽视编译器错误信息 问题: Concepts错误信息通常更为明确,但如果忽视这些信息,可能会错过解决问题的关键线索。...解决: 仔细阅读编译器提供的错误信息,它们往往能直接指出哪个概念没有被满足,从而快速定位问题。 2....五、总结 Concepts的引入,标志着C++模板编程进入了新的时代,它不仅提升了代码的清晰度和可维护性,还极大地改善了编译时错误信息的质量。...随着C++20及其后续版本的普及,掌握并有效利用Concepts将成为现代C++程序员不可或缺的技能之一。

    62210

    C++一分钟之概念(concepts):C++20的类型约束

    在C++的漫长进化历程中,Concepts(概念)作为C++20引入的一个重大特性,为模板编程带来了革命性的变化。...它允许程序员以更加清晰、直观的方式表达类型要求,从而提高代码的可读性和错误信息的友好度。...忽视编译器错误信息问题: Concepts错误信息通常更为明确,但如果忽视这些信息,可能会错过解决问题的关键线索。...解决: 仔细阅读编译器提供的错误信息,它们往往能直接指出哪个概念没有被满足,从而快速定位问题。2....五、总结Concepts的引入,标志着C++模板编程进入了新的时代,它不仅提升了代码的清晰度和可维护性,还极大地改善了编译时错误信息的质量。

    33010

    C++ typename的双重含义

    但是对于编译器而言,在没有明确C的定义之前,是无法确定a是一个嵌套于C中的类型,其实a可能是C内一个静态成员变量,假设x刚好是一个全局变量,那么这行代码也可以由编译器解析为两数相乘。...编译器面对这样的代码如何处置?...编译器会这样处理:如果在template中遇到一个嵌套从属类型名称,即依赖于模板类型参数的类型,放在上面例子中对应C::a,C::a依赖于模板类型参数C,它便假设这个名称不是个类型,除非显示告诉编译器。...typename不可以出现在base classes list(所继承的基类成员列表)内的嵌套从属类型名称之前,也不可以在member initialization list(成员初始化列表)中作为base...---- 参考文献 [1]Effective C++:改善程序与设计的55个具体做法(第3版 中文版)[M].条款四十二:了解typename的双重意义

    1.3K20

    C++那些事之template disambiguator

    disambiguator 1.背景 最近看到一段代码: auto chunk_left = first_sort_key.template GetChunk(left); 请问,这里的....2.template disambiguator 在C++中,当使用模板的依赖名称(dependent names)时,有时需要使用模板消除符(template disambiguator)来帮助编译器区分这些名称...所谓"dependent names"是指依赖于模板参数的类型或值,编译器不能在实例化模板之前确定它们的具体含义。这可能会导致编译器在解析这些名称时产生二义性。...模板消除符(template disambiguator)使用关键字"template"来明确告诉编译器一个特定的名称是一个模板。这样编译器就可以正确地解析该名称,而不会产生二义性。...::value_type v; 官方资料: https://en.cppreference.com/w/cpp/language/dependent_name 假设有下面这个代码,我们如果不加.template

    18620

    C++泛型编程泛泛谈

    里面还有一个日语写的程序段,感觉有点莫名其妙的可可爱爱 而且C++研究的越多越觉得,范型编程或者说通用编程才是C++这个语言的灵魂,在2022年还拿C++和C比的人,我只能说你格局太low了,朋友~...模板是 C++ 中的泛型编程的基础。作为强类型语言,C++ 要求所有变量都具有特定类型,由程序员显式声明或编译器推导。但是,许多数据结构和算法无论在哪种类型上操作,看起来都是相同的。...编译器从模板生成类或函数的过程称为“模板实例化”;minimum 是模板 minimum 的实例化。 当编译器遇到一个模板定义的时候,它并不会生成代码。...只有我们实例化出模板的一个特定的版本时,编译器才会生成其对应的代码。当我们使用(而不是定义)模板时,编译器才会生成代码。这个特性影响我们如何组织代码以及错误何时才可以被检测到。...编译出现错误的时机: 第一阶段,编译模板本身时,该时期所出现的错误大多数为语法错误; 第二阶段,编译器遇到模板使用时; 第三阶段,模板实例化时,而只有在这个阶段才能发现类型相关的问题。

    1K30

    C++精通之路:map和set的介绍和有关oj题

    : template struct pair { typedef T1 first_type; typedef T2 second_type; T1 first...set在底层是用二叉搜索树(红黑树)实现的 2. set的使用 set的模板参数列表: T: set中存放元素的类型,实际在底层存储的键值对。...C++中的multiset multiset容器与set容器实现和接口基本一致,唯一区别就是,multiset允许键值冗余,即multiset容器当中存储的元素是可以重复的 注意:对于find来说multiset...键值 key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起, 为其取别名称为pair: typedef pair value_type;...map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))二:map的使用 map的模板参数说明: key: 键值对中key的类型 T: 键值对中value的类型 Compare:

    37920

    【C++高阶】高效数据结构的探索(map&&set)

    里面存储的是元素本身 关联式容器(Associative Containers) 是C++标准模板库(STL)中的一类重要容器,主要用于存储和快速检索键值对(key-value pairs)形式的数据。...T2 second_type; T1 first; T2 second; pair(): first(T1()), second(T2()) {} pair(const T1& a,...常见的关联式容器包括set、multiset、map和multimap等,它们在不同的应用场景下提供了高效的解决方案 4. set && multiset set的概念 概念: set 是 C++ 标准模板库...是 C++ 标准库 中的一个容器,它允许存储重复的元素。...key: 键值对中key的类型 T: 键值对中value的类型 Compare: 比较器的类型,默认按小于比较 insert 在insert插入中,所需要的元素类型是value_type - > pair

    11310
    领券