为何无法在子程序声明中使用limited with包中的子类型?
关于Ada 2012中
limited with无法访问子类型的问题 Ada 2012的limited with机制原本用于处理循环依赖的类型场景,比如两个包互相需要引用对方的类型时,可以通过不完全类型声明配合limited with打破循环。例如:
type Point; type Line; -- 不完全类型声明 type Point is record L, M, N: access Line; end record; type Line is record P, Q, R: access Point; end record;
(示例来自John Barnes《Programming in Ada 2012》第13.5节“相互依赖类型”)
但我在使用gcc -fdump-ada-spec -C从C头文件自动生成Ada代码时遇到了问题:生成的代码用limited with导入包后,能正常访问包中的常规类型,但无法访问子类型,编译时报错“子类型未在包中声明”。
代码示例
provider.ads
package Provider is type Fine_Type is range 0 .. 10_000; subtype Bad_Type is Fine_Type; end Provider;
user.ads
limited with Provider; package User is procedure Do_It (A : access constant Provider.Bad_Type); end User;
user.adb
package body User is procedure Do_It (A : access constant Provider.Bad_Type) is begin null; end Do_It; end User;
limited_with_test.gpr
project limited_with_test is for Source_Dirs use ("src"); for Main use ("main.adb"); for Exec_Dir use "bin"; for Object_Dir use "obj"; for Create_Missing_Dirs use "True"; end limited_with_test;
编译错误
将源码放入src目录后执行gprbuild,得到如下错误:
$ gprbuild using project file limited_with_test.gpr Compile [Ada] main.adb user.ads:5:49: error: "Bad_Type" not declared in "Provider" gprbuild: *** compilation phase failed
原因分析
Ada的limited with导入机制仅提供包的不完全视图,它的可见性范围非常有限:
- 只有包中的**顶级类型(包括私有类型)**会被视为不完全类型而可见,用于声明访问类型(
access)或者作为参数的不完整类型引用。 - 子类型、常量、子程序、枚举值等都不属于不完全视图的可见部分,因此在
limited with导入的包中无法直接引用子类型Bad_Type。
而常规类型Fine_Type能被访问,是因为它属于顶级类型,符合limited with的可见性规则。
解决方法
根据场景选择合适的方案:
- 改用普通
with导入:如果User和Provider之间没有循环依赖,直接把limited with Provider;替换成with Provider;,即可正常访问子类型。 - 替换为基础类型:如果必须保留
limited with(比如存在循环依赖),可以在User的声明中使用基础类型Provider.Fine_Type代替子类型Bad_Type,在包体中再转换为子类型使用。 - 重构包结构:将需要暴露的子类型放到独立的子包中,再用
limited with导入这个子包,避免主包的循环依赖问题。
内容的提问来源于stack exchange,提问作者TamaMcGlinn
相关产品推荐
相关产品推荐

