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

为什么我们不能得到一个指向泛型结构的指针?

在C++中,泛型结构是通过模板来实现的,它可以根据不同的数据类型生成不同的结构。然而,由于泛型结构的实例化是在编译时完成的,而指针的类型是在运行时确定的,因此我们不能直接得到一个指向泛型结构的指针。

当我们定义一个泛型结构时,编译器会根据使用该结构时传入的具体类型生成对应的代码。这意味着每个具体类型都会生成一个独立的结构,它们在内存中的布局和大小可能是不同的。因此,如果我们尝试将一个指向泛型结构的指针赋值给一个指针变量,编译器无法确定该指针变量应该指向哪个具体类型的结构,从而导致编译错误。

为了解决这个问题,我们可以使用模板特化来实现指向泛型结构的指针。模板特化是指为特定的数据类型提供特定的实现。通过为每个具体类型提供特定的结构定义和相关操作,我们可以在编译时确定指针的类型,并使用指向特定类型结构的指针。

总结起来,我们不能直接得到一个指向泛型结构的指针,因为泛型结构的实例化是在编译时完成的,而指针的类型是在运行时确定的。要实现指向泛型结构的指针,可以使用模板特化来为特定的数据类型提供特定的实现。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

c语言链表指向一个结构指针,结构体和它众多小细节

所以我么就可以定义一个学生结构体,里面包含了他各种属性,只是需要注意我们只是定义了一种数据类型,如果要向内存申请存储单元还要继续声明变量。...在这里还有一个小细节,就是对于字符串处理。字符串不能被赋值,只能采用字符数组或者字符拷贝函数strcpy()等方式处理。字符串名字表示首地址,是地址常量,常量不能被赋值。...我们在之前提到,想对某一段一段内存进行操作前提是【把该变量表示出来】。 对于结构指针,可以望名知意:这是一个指针,只不过这个指针里面存放地址是一个结构体变量地址。...对结构指针而言,访问它所指向结构变量成员可以采用取值运算符*,比如struct (*stu).name。当然,我们在实践中更喜欢采用方式是箭头方式:struct stu->name。...只是对于初学者而言,可能很难理解为结构指针类型起别名方式。这里只需把它当作一种等价替换就可以,为结构指针起别名之后会把指针标志*给藏起来,但是在实际使用中要时刻注意,这仍旧是一个指针

1.1K21

和元编程模型:Java, Go, Rust, Swift, D等

基本想法 假设我们用一种没有系统语言进行编程,我们想实现一个通用堆栈数据结构,它对任何数据类型都有效。...这种方法叫做 "vtables"(由 "虚拟方法表 "缩写而来),它实现方式是,在通用结构每个对象偏移量为0地方,都有一个指向函数指针指针。...当你把一个类型转换为一个接口类型时,它会创建一个包装器,这个包装器包含一个指向原始对象指针一个指向该接口特定类型函数vtable指针。...动态类型语言 反射是非常强大,可以完成很多不同元编程任务,但有一点它不能做,那就是创建新类型或编辑现有字段类型信息。如果我们增加了这样能力,并通过反射来实现,最终就会得到动态类型语言。...,这也是为什么Rust可以使用同一个类型系统来支持这两种原因!

3K30

会让你 Go 代码运行变慢

整个过程跟设计文档说明完全相符:用于传递指向结构 stenciling 过程会将指针单态化为类似 void 指针。单态化期间不考虑指向对象其他属性,因此无法进行内联。...这样,函数调用一个参数就必须是 buf.(*face).data,即指向我们接口内 strings.Builder 实际指针。...出于这一现实,stenciling 实现才需要向每一个型函数调用传递字典:字典中包含,就是指向函数所有参数 itab 指针。 说到这里,大家应该理解为什么我们程序集要费力使用字典了。...这就是我们从分析中得到一个结论:在 1.18 中,我们没必要将带有接口纯函数转换成型函数,因为 Go 编译器目前无法生成通过指针调用方法函数 shape,所以转换只会拖慢代码运行速度。...所以,我们得到一个明确结论:千万别把接口传递给 Go 中型函数。即使在最理想情况下,即接口与约束完全匹配时,指向类型每一次方法调用都会产生大量开销。

1.1K20

会让你 Go 代码运行变慢

整个过程跟设计文档说明完全相符:用于传递指向结构 stenciling 过程会将指针单态化为类似 void 指针。单态化期间不考虑指向对象其他属性,因此无法进行内联。...这样,函数调用一个参数就必须是 buf.(*face).data,即指向我们接口内 strings.Builder 实际指针。...出于这一现实,stenciling 实现才需要向每一个型函数调用传递字典:字典中包含,就是指向函数所有参数 itab 指针。 说到这里,大家应该理解为什么我们程序集要费力使用字典了。...这就是我们从分析中得到一个结论:在 1.18 中,我们没必要将带有接口纯函数转换成型函数,因为 Go 编译器目前无法生成通过指针调用方法函数 shape,所以转换只会拖慢代码运行速度。...所以,我们得到一个明确结论:千万别把接口传递给 Go 中型函数。即使在最理想情况下,即接口与约束完全匹配时,指向类型每一次方法调用都会产生大量开销。

1.2K40

Golang 实现原理

提供了一种更灵活、更通用方式来编写函数和数据结构,以处理不同类型数据,而不必针对每种类型编写重复代码。 1.有 interface{} 为什么还要有?...以下是 Go 实现基本原理: 2.1 类型参数 Go 使用类型参数来实现通用性。在定义函数、数据结构或方法时,可以声明一个或多个类型参数。...在函数体内,可以使用 T 来表示参数和返回值类型。 数据结构 也可以用于创建通用数据结构,如切片、映射等。这样可以更灵活地处理不同类型数据。...这样做是因为指针看起来总是一样,不管它指向是什么类型。 如果这些值是对象,而型函数需要调用这些对象方法,它就不能再这样做了。该函数只有一个指向对象指针,不知道它们方法在哪里。...参考wenxian An Introduction To Generics 设计 - | Go 语言设计哲学- 煎鱼 golang拾遗:为什么我们需要- apocelipes 简单易懂

29610

【笔记】C++标准库: 体系结构与内核分析(上)

只朝尾部单向扩充, 不能添加元素在头部, 通常用push_back()压入数据 序列 list 双向链表 1. 每次增长只扩充一个节点 2....对于模板编程, 有一个很实用设计在STL中非常常见: 特化(Specialization), 相对普通模板编程叫做化, 特化又可以细分为全特化和偏特化, 这种写法使得我们能保留化函数通用性情况下...它们分别是: value_type: 迭代器所指向数据实际类型, 通常是T difference_type: 迭代器做差得到类型(索引距离), 通常是 ptrdiff_t pointer: 迭代器所指向数据指针类型...()需要random_access_iterator_tag迭代器 萃取器Traits 算法本来可以直接访问迭代器等类来得知所需额外信息, 但是为了用性, 我们也希望算法可以直接应用在原生指针上...由于rb_tree属于一种排序二叉树, 所以按照正确规则进行遍历的话树中节点将以排序顺序得到. rb_tree结构只有一个指向header节点指针和记录节点数量值.

1.1K30

为什么会让你Go程序变慢

inteface 是一个 16 bytes 指针实现结构体名 iface, 第一个指针指向接口元数据信息 itab, 第二个指针指向值本身 type iface struct { tab *...WriteByte 方法,我们需要指向 itab 指针。...) 如果你还记得,这就是为什么 go 所谓模版化实现(stenciling), 要给每个型函数调用传递一个字典 dictionary 全部原因:这个字典包含指向函数所有参数 itab 指针...但令人惊讶是:型函数也是 3 allocs/op, 尽管生成函数实例化直接使用了指针,但 escape analysis 不能再证明它是 non-escape, 所以我们得到一个额外堆分配。...现在它可以做一些非常强大事情,当不碍事时候 让我给你举个例子:想象一下我们正在开发一个库,为 Go 增加函数式调用。我们为什么要这样做呢?我也不知道。很多人似乎都在做这件事。

23830

C#基础知识系列二(值类型和引用类型、可空类型、堆和栈、装箱和拆箱)

在释放变量时候,其顺序总是与给它们分配内存顺序相反,后进先出,这就是堆栈工作方式。 堆栈是向下填充,即从高地址向低地址填充。当数据入栈后,堆栈指针就会随之调整,指向一个自由空间。...我们来举个例子说明。 ? 如图,假如堆栈指针2000,下一个自由空间是1999。下面的代码会告诉编译器需要一些存储单元来存储一个整数和一个双精度浮点数。...此时,堆栈指针就减4,指向已用空间末尾1996,下一个自由空间为1995。下一行声明d赋值3.5后,double需要占用8个字节,所以存储在1988~1995上,堆栈指针减去8。   ...变量生存期总是嵌套,当d在作用域时候,无论发生什么事情,都可以保证堆栈指针一直指向存储d空间。删除这个d变量时候堆栈指针递增8,现在指向d曾经使用过空间,此处就是放置闭合花括号地方。...可以看出可以避免装箱拆箱带来不必要性能消耗;当然好处不止于此,还可以增加程序可读性,使程序更容易被复用等等,至于以后再做详细介绍。

1.1K41

C#基础知识系列二(值类型和引用类型、可空类型、堆和栈、装箱和拆箱)

在释放变量时候,其顺序总是与给它们分配内存顺序相反,后进先出,这就是堆栈工作方式。 堆栈是向下填充,即从高地址向低地址填充。当数据入栈后,堆栈指针就会随之调整,指向一个自由空间。...我们来举个例子说明。 ? 如图,假如堆栈指针2000,下一个自由空间是1999。下面的代码会告诉编译器需要一些存储单元来存储一个整数和一个双精度浮点数。...此时,堆栈指针就减4,指向已用空间末尾1996,下一个自由空间为1995。下一行声明d赋值3.5后,double需要占用8个字节,所以存储在1988~1995上,堆栈指针减去8。   ...变量生存期总是嵌套,当d在作用域时候,无论发生什么事情,都可以保证堆栈指针一直指向存储d空间。删除这个d变量时候堆栈指针递增8,现在指向d曾经使用过空间,此处就是放置闭合花括号地方。...可以看出可以避免装箱拆箱带来不必要性能消耗;当然好处不止于此,还可以增加程序可读性,使程序更容易被复用等等,至于以后再做详细介绍。

1.1K10

Golang interface 接口详细原理和使用技巧

任何一个 interface{} 类型变量都包含了2个指针一个指针指向类型,对应 pair 中 type,这个 type 类型包括静态类型 (static type,比如 int、string......)和具体类型(concrete type,interface 所指向具体类型),另外一个指针指向实际值,对应 pair 中 value。...主要原因有如下几点: 可以实现编程(虽然 Go 在 1.18 之后已经支持了) 在 C++ 等高级语言中使用编程非常简单,但是 Go 在 1.18 版本之前,是不支持,而通过 Go...使用时候不管数组元素类型是什么类型(int, float, string…),只要我们实现了这三个方法就可以使用 Sort 函数,这样就实现了“编程”。...因为一个 interface{} 类型变量包含了2个指针一个指针指向类型,另外一个指针指向实际值。

99720

《Rust for Rustaceans》 样章试译 | 第二章 Rust 基础

我们可以通过解引用(dereference)指针来访问存储在它所指向内存位置值。也可以在多个变量中存储相同指针,这些变量正确地指向内存中一个位置,从而指向相同值。...但你不能改变所指向值(即 x 值)。同样,你可以通过z来改变y指针值,但你不能改变 z 自身,使其指向一个不同值。...那么,当涉及到生存期时候,为什么需要学习变呢?当你考虑生存期如何与借用检查器交互时,变就变得相关了。考虑清单2-11中所示类型,它在一个字段中使用了多个生存期。...("{}", s); // 清单 2-11: 需要多个生存期类型 乍一看,在这里使用两个生存期似乎没必要,我们没有任何方法需要区分结构中不同部分借用,就像清单2-10中StrSplit那样...我们将讨论类型如何在内存中表示,看看和特质(trait)如何产生执行代码,并看看 Rust 为更高级用例提供一些特殊类型和特质结构

5.4K31

【C++】list使用和基本迭代器框架实现 & vs和g++下string结构说明

,是一个自定义类型,并非原生指针内置类型,所以解引用迭代器我们拿到结构体对象,而并非是数据内容,这就不符合迭代器特征,因为迭代器本意就是要解引用拿到数据,而我们拿到一个结构体对象,这就有问题了...用一个结点指针就可以作为list迭代器成员变量了,迭代器本质就是一个对象,这个对象成员变量是结构指针,通过迭代器类和迭代器对象我们才能让list迭代器实现解引用加加减减等操作。 5....* _prev;//指向一个结点结构指针 T _data;//数据类型是,可能是内置类型,也有可能是自定义类型 list_node(const T& x) //new结点时候会调用构造函数...,new会自动调用node类带参构造函数,我们给构造函数传一个匿名对象, //保证结点存储数据类型是,既有可能是内置类型也有可能是自定义类型,所以传匿名对象。...下面所说默认环境是32位平台,指针为4字节。从打印结果我们可以得到两个信息,一个是s1和s2所占字节大小一样,另一个是两者所占字节大小为28字节。

47010

为什么指针被誉为 C 语言灵魂?

对,就是指针,你可以这样: int *pa = &a; pa 中存储就是变量 a 地址,也叫做指向 a 指针。 在这里我想谈几个看起来有点无聊的话题: 为什么我们需要指针?...不管几级指针有两个最核心东西: 指针本身也是一个变量,需要内存去存储,指针也有自己地址 指针内存存储是它所指向变量地址 这就是我为什么多级指针是逻辑上概念,实际上一块内存要么放实际内容,要么放其它变量地址...下面的例子就 是一个 void 指针: void *ptr; void 指针最大用处就是在 C 语言中实现编程,因为任何指针都可以被赋给 void 指针,void 指针也可以被转换回原来指针类型...不过也有需要注意: 不能对 void 指针解引用 比如: int num; void *pv = (void*)# *pv = 4; // 错误 为什么?...但是 void,编译器是不知道它到底指向是 int、double、或者是一个结构体,所以编译器没法对 void 指针解引用。

70310

坚持还是放弃,Go语言“美好与丑陋”解读

由于内置集合(map,slice 和 array)是引用并且是可变,所以复制包含其中之一结构体只会将复制指向同一后台内存指针。 下面的示例说明这一点: ?...对 Bang 调用成功了,因为它应用在指向 Bomb 指针上:不需要解引用该指针来调用该方法。Boom 方法操作一个值,因此一个调用导致指针被解引用,这会导致 panic。...没有......至少不适合你 很难想象一个没有现代静态类型语言,但这就是你用 Go 得到东西:它没有......或者更确切地说几乎没有,正如我们将看到那样,这使得它比没有更糟糕...然而,没有用户可定义数据结构。这意味着你无法以类型安全方式定义可用于任何一个 type 可复用 abstractions。...正如接下来我们将看到,把内置与用户定义分隔开,对开发者“舒适度”和编译时类型安全产生了影响:它影响了整个Go生态系统。

1.4K41

透过 Rust 探索系统本原:

他说,目前我们走了三步: 第一步,通用计算机体系结构:将内存视作一组连续可寻址空间 第二步,通用计算机语言:使用指针作为统一引用类型标识符 第三步,编程 今天我们就来讲讲编程。...这会生成一个 Trait Object,在上图中,我们可以看到,Trait Object 底层逻辑不过就是胖指针(fat pointer) —— 一个包含两个指针数据结构。...其中,一个指针指向数据本身,另一个指向虚函数表(vtable)。...当然,C++/Java 指向 vtable 指针在编译时放在类结构里,而 Rust 放在 Trait object 中。...支持语言并不能帮助你更好地做编程,就好比给我一台斯坦威钢琴,并不意味着我就具备了演奏李斯特《钟》能力。

1.1K40

程序员C语言快速上手——高级篇(十)

例如将数组声明为全局数组变量,那么就必须在声明时静态指定数组长度。假如我们一个数组来存放会员注册信息,那么我们根本不能在编译时确定数组具体长度,显然我们需要一个可以动态增长内存区域。...我们知道数组变量实际上也是一个指针指向数组起始地址,结构指针也是指向一个成员变量起始地址,而函数指针亦是指向函数起始地址。 所谓函数指针,就是一个保存了函数起始地址指针变量。...首先思考一个问题,指针仅仅是用来保存一个内存地址,所有的内存地址都只是一个号码,那么指针为什么还需要类型呢?理论上所有的指针都应该是同一种类型才对呀?...接触过Java等具有面向对象编程语言的人,可能马上就会联想到,是的,C语言没有,但是利用void*指针特点,我们可以使用一些技巧来模拟编程。...像Java这样编程语言存在我们可以定义,而不需要在函数声明时指定具体类型,当调用时候传入是什么类型,函数就计算什么类型,我们看一下C语言如何实现 // 交换两个变量值 void swap

1.4K30

Python源码剖析:深度探索Cpython对象-达观数据

在 Python 中创建一个对象,会分配内存并进行初始化,然后 Python 会用一个 PyObject * 来保存和维护这个对象,因此在 Python 中,变量传递(包括函数参数传递)实际上传递都是一个指针...这个指针具体指向什么类型对象我们并不知道,只能通过其内部 ob_type 成员进行动态判断,而正是因为这个 ob_type,Python 实现了多态机制。...因为我们说 Python 中变量都是一个 PyObject *,所以它可以指向任意对象,因此 Python 就无法做基于类型方面的优化。...事实上,Python 内部创建一个对象方法有两种:• 通过 Python/C API,可以是API、也可以是特型API,用于内置类型• 通过对应类型对象去创建,多用于自定义类型Python 对外提供了...以 f = 3.14 为例,底层结构如下:使用 API 创建使用特型 API 创建综上,不管采用哪种方式创建,最终关键步骤都是分配内存,创建内置类型实例对象,Python 是可以直接分配内存

24110

一文带你读懂 Java

一、使用和类型擦除 本质上是参数化类型(paramentersized type)应用,可以声明在类、接口或者方法上。...没有时可以用Object结合强制类型转化实现相似需求,但是运行时风险就明显了,就是用于解决这个问题。...属性表中有个Code属性,即是方法编译成后字节码指令序列,擦除仅仅是擦除Code表中信息。...Java内存模型 信息以参数化类型信息(paramentersized typ)方式存储在对象类型实例(即方法区中Class)中,各种实例类型指针指向方法区中同一class类型实例。...四、配合反射获取信息 我们定义一个类 open class SuperClass { } class TestClass: SuperClass()

31520

C++复习篇

25.型函数模板(兼容不同类型) 26.类模板(兼容不同类型) 27.数值型函数模板和数值类模板(兼容不同数值) 28.C++智能指针 29.Qt中智能指针 1.const const和define...所以函数模板,其实只是一个模具,当我们调用它时,编译器就会给我们生成真正函数....(兼容不同数值) 数值类似,但是数值型模板必须在编译时被唯一确定 示例1-数值型函数模板: template //定义一个值T,还有个int数值...头文件 1)auto_ptr 生命周期结束时,自动摧毁指向内存空间 不能指向堆数组(因为auto_ptr析构函数删除指针是delete,而不是delete[]) auto_ptr...构造函数为explicit类型,所以只能显示初始化 提供get()成员函数,可以用来查看类里指针地址 一个堆空间永远只属于一个对象(比如auto_ptr被拷贝/赋值,则自身指针指向地址会被抢占)

1.3K20

C++基本语法

c++中提供指针变量存储对象地址,指针运算会被编译器优化为地址运算,比如一个int类型指针 p+1值实际是p指向地址+1个int所占空间大小后逻辑地址 指针语法为 typename *...functionPointer作为类型可以定义指向 返回值为void,只有一个int形参函数指针 c++11标准给using指令也加入了取别名用法(真希望可以废弃一些旧用法,太多重复东西)。...上述代码等价于 using iint = int; using functionPointer = void (*)(int a); c++通过template来设定,方法代表该方法尚未注册实际代码...,只有在代码里调用了该方法时,会通过隐式触发或者显示定义或者主动触发来创建对应方法实例 方法匹配规则为 代码中指定方法>普通方法>显示声明>方法 如 //在一些标准好像typename...,但是无法通过p1修改单元内容 p2不可修改指向地址,但是可以通过p2修改单元内容 mutable mutable用于标记结构体中不想受结构const限制成员,比如 const struct data

1K20
领券