为什么必须通过 this 指针访问模板基类成员?

2024-06-03

如果下面的类不是模板,我可以简单地拥有x in the derived班级。但是,通过下面的代码,我have to use this->x. Why?

template <typename T>
class base {

protected:
    int x;
};

template <typename T>
class derived : public base<T> {

public:
    int f() { return this->x; }
};

int main() {
    derived<int> d;
    d.f();
    return 0;
}

简短的回答:为了x依赖名称,以便延迟查找,直到知道模板参数为止。

长答案:当编译器看到模板时,它应该立即执行某些检查,而不会看到模板参数。其他的则推迟到知道参数为止。这称为两阶段编译,MSVC 不这样做,但标准要求它并由其他主要编译器实现。如果您愿意,编译器必须在看到模板后立即对其进行编译(编译为某种内部解析树表示形式),并将实例化推迟到稍后进行编译。

对模板本身而不是对其特定实例执行的检查要求编译器能够解析模板中代码的语法。

在 C++(和 C)中,为了解析代码的语法,有时需要知道某物是否是类型。例如:

#if WANT_POINTER
    typedef int A;
#else
    int A;
#endif
static const int x = 2;
template <typename T> void foo() { A *x = 0; }

如果 A 是一个类型,则声明一个指针(除了隐藏全局变量之外没有任何作用)x)。如果 A 是一个对象,那就是乘法(除非某些运算符重载它是非法的,分配给右值)。如果是错误的,必须诊断这个错误在第一阶段,它被标准定义为错误在模板中,而不是在它的某些特定实例中。即使模板从未实例化,如果 A 是int那么上面的代码是错误的,必须进行诊断,就像如果foo根本不是一个模板,而是一个简单的函数。

现在,标准规定了哪些名称aren't依赖于模板参数必须可以在第 1 阶段解决。A这里不是一个从属名称,它指的是同一事物,无论类型如何T。所以需要在定义模板之前定义它,以便在第一阶段被找到和检查。

T::A将是一个依赖于 T 的名称。在第一阶段我们不可能知道这是否是一个类型。最终将用作的类型T在实例化中,很可能尚未定义,即使定义了,我们也不知道哪种类型将用作模板参数。但我们必须解决语法问题,以便对格式错误的模板进行宝贵的第一阶段检查。因此,标准对依赖名称有一条规则 - 编译器必须假设它们是非类型,除非用typename指定他们are类型,或在某些明确的上下文中使用。例如在template <typename T> struct Foo : T::A {};, T::A用作基类,因此明确是一种类型。如果Foo使用具有数据成员的某种类型进行实例化A而不是嵌套类型 A,这是执行实例化的代码中的错误(第 2 阶段),而不是模板中的错误(第 1 阶段)。

但是带有依赖基类的类模板又如何呢?

template <typename T>
struct Foo : Bar<T> {
    Foo() { A *x = 0; }
};

A 是否是从属名称?有了基类,any名称可以出现在基类中。因此我们可以说 A 是一个从属名称,并将其视为非类型。这会产生不良影响每个名字Foo 中是依赖的,因此每种类型Foo 中使用的(内置类型除外)必须经过限定。在 Foo 内部,您必须编写:

typename std::string s = "hello, world";

because std::string将是一个从属名称,因此除非另有说明,否则假定为非类型。哎哟!

允许您的首选代码的第二个问题(return x;)是即使Bar之前已定义Foo, and x不是该定义中的成员,有人可以稍后定义一个专门化Bar对于某些类型Baz,使得Bar<Baz>有一个数据成员x,然后实例化Foo<Baz>。因此,在该实例化中,您的模板将返回数据成员,而不是返回全局成员x。或者相反,如果基本模板定义Bar had x,他们可以在没有它的情况下定义专业化,并且您的模板将寻找全局x返回Foo<Baz>。我认为这被认为与你遇到的问题一样令人惊讶和痛苦,但它是silently令人惊讶,而不是抛出令人惊讶的错误。

为了避免这些问题,有效的标准规定,除非明确要求,否则不会考虑搜索类模板的依赖基类。这会阻止一切事物仅仅因为可以在依赖库中找到而依赖它。它还具有您所看到的不良效果 - 您必须限定基类中的内容,否则找不到它。常见的制作方法有以下三种A依赖:

  • using Bar<T>::A;在课堂里 -A现在指的是某事Bar<T>,因此依赖。
  • Bar<T>::A *x = 0;在使用时 - 再次,A肯定是在Bar<T>。这是乘法,因为typename没有使用,所以可能是一个坏例子,但是我们必须等到实例化才能确定是否operator*(Bar<T>::A, x)返回一个右值。谁知道呢,也许确实如此……
  • this->A;在使用时 -A是会员,所以如果它不在Foo,它必须位于基类中,标准再次指出这使其具有依赖性。

两阶段编译既繁琐又困难,并且对代码中的额外冗长引入了一些令人惊讶的要求。但就像民主一样,除了所有其他方式之外,它可能是最糟糕的做事方式。

您可以合理地认为,在您的示例中,return x;没有意义如果x是基类中的嵌套类型,因此该语言应该 (a) 说它是一个从属名称,并且 (2) 将其视为非类型,并且您的代码无需使用this->。在某种程度上,您是不适用于您的情况的问题的解决方案所造成的附带损害的受害者,但是您的基类仍然存在问题,可能会在您下面引入影子全局变量的名称,或者没有您认为的名称他们有,并且发现了一个全球性的东西。

您还可能认为默认值应该与依赖名称相反(假设类型除非以某种方式指定为对象),或者默认值应该对上下文更加敏感(在std::string s = "";, std::string可以被理解为一种类型,因为没有其他任何东西具有语法意义,即使std::string *s = 0;是有歧义的)。再说一次,我不太清楚这些规则是如何商定的。我的猜测是,所需的文本页数会减少创建许多特定规则,以确定哪些上下文采用类型,哪些上下文采用非类型。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么必须通过 this 指针访问模板基类成员? 的相关文章

  • 使用 xmlns 属性(命名空间)查询 XDocument

    我尝试从 Visual Studio csproj 文件查询元素 我创建了一个简短的示例来说明该问题 Working string xml1
  • 替换大字符串中的多个字符串的最快方法

    我正在寻找替换大 1mb 字符串的多个 500 子字符串的最快方法 无论我尝试过什么 String Replace 似乎都是最快的方法 我只关心最快的方式 不是代码的可读性 可维护性等 我不在乎是否需要使用不安全的代码或预处理原始字符串 每
  • 可以作为参数传递给 POST 方法的对象的最大大小

    我有一个带有 POST 方法的 Web API 控制器 如下所示 public class MyController ApiController POST api Scoring public HttpResponseMessage Pos
  • 共享库 C++ Makefile

    我需要编译胖二进制文件才能在另一台 Linux 机器上使用它 但缺少一些库 因此据我了解 我应该使用一些 shared 选项来编译它 但我不明白如何为此配置 Makefile 目前我的 makefile 如下所示 CC g CC FLAGS
  • 不同平面中不同幅值的两条线段之间最近的两个 3D 点

    比方说AB1 AB2 CD1 CD2 AB1 AB2 and CD1 CD23D 点构成线段 所说的线段是不在同一平面 AP是一个点 线段AB1 AB2 BP是一个点 线段CD1 CD2 Point1 and Point2彼此最接近 两条线
  • 无符号长十六进制表示

    include
  • C++ 中的结构填充

    如果我有一个struct在 C 中 有没有办法安全地将其读 写到跨平台 编译器兼容的文件中 因为如果我理解正确的话 每个编译器都会根据目标平台进行不同的 填充 不 那是不可能的 这是因为C 在二进制层面缺乏标准化 Don Box http
  • iText7 RegexBasedLocationExtractionStrategy 如何获取找到的文本的字体名和字体大小

    我尝试在 C 上使用 iText7 进行文本替换 我只能使用 RegexBasedLocationExtractionStrategy 获取搜索文本的内容和矩形 并且我想获取文本的字体和大小 有什么建议么 谢谢 你可以实施IText提取策略
  • WCF:通用接口的序列化可能吗?

    我正在尝试实现一个服务契约 其中包含一个采用通用接口的方法 并且该通用接口本身被赋予一个接口参数 我用 ServiceKnownType 装饰了服务接口 用常规 KnownType 装饰了服务实现 并用常规 KnownType 装饰了数据契
  • 来自“void *”的dynamic_cast

    根据this https stackoverflow com questions 3155277 cannot dynamic cast void to templated class void 没有 RTTI 信息 因此从void 不合法
  • 查询 XmlDocument 而不会出现“命名空间前缀未定义”问题

    我有一个 Xml 文档 它定义并引用了一些命名空间 我将其加载到 XmlDocument 对象中 据我所知 我创建了一个 XmlNamespaceManager 对象 用于查询 Xpath 问题是我收到命名空间 my 未定义的 XPath
  • Java 错误:默认构造函数未定义隐式超级构造函数

    我有一些简单的 Java 代码 其结构与此类似 abstract public class BaseClass String someString public BaseClass String someString this someSt
  • 传递给 WCF 服务的可选查询字符串参数

    我想知道如何使用 string limit WebOperationContext Current IncomingRequest UriTemplateMatch QueryParameters Limit 在我的wcf中这个方法 Cit
  • 当调试器退出且没有调用堆栈时,用于跟踪 C# 崩溃的工具?

    我有一个大型 复杂的 C GUI 应用程序 它以完全可重现的方式崩溃 但我无法轻松诊断崩溃的原因 因为调试会话不是以通常的方式使用调用堆栈破坏调试器 而是完全退出 唯一的提示是输出窗口末尾有一条消息 STATUS STACK BUFFER
  • MVC - 从视图调用控制器

    我是 MVC 新手 我正在使用 MVC 开发一个 Web 应用程序 该应用程序仅包含一个页面 所以在这个视图中我必须填充多个数据 假设应用程序是 新闻提要 应用程序 我需要填充最近的新闻 您喜欢的新闻 您朋友推荐的新闻等 那么我应该从视图到
  • 如何隐藏鼠标光标?

    我想问是否有人可以为我提供一个 C 代码 在其中我可以在按下特定键时隐藏 显示鼠标指针 我发现一些只为 TURBO C 编写的代码 它们都不能使用 dev c 甚至 Visual c 编译和运行 我尝试运行在 Dev C 中找到的代码 但我
  • C# 固定长度的字符串对象

    我有一堂课 我想使用固定大小的字符串 固定大小的原因是该类 序列化 为文本文件 具有固定长度的值 我想避免为每个值编写一个保护子句 而是让类处理它 所以我有大约 30 个属性 看起来像这样 public String CompanyNumb
  • 如何获取字典元素的相对位置?

    我有下一个 C 代码 Dictionary
  • 我使用 difftime 的 c 函数有时会返回 65535

    我有一个函数 使用 difftime 来检测自通信心跳停止以来的时间 以秒为单位 该函数的运行速度可以达到每 50 毫秒一次 该函数似乎可以工作 除了偶尔返回 65535 之外 我可以将执行次数减少到每秒一次 因为 difftime 的返回
  • 将用户控件绑定到 bool 属性的相反值

    非常简单 我想做同样的事情this https stackoverflow com questions 534575 how do i invert booleantovisibilityconverter但在winforms中 谷歌似乎提

随机推荐

  • PDF:在现有 PDF 文件中插入一行文本

    我有一个 PDF 文件 我希望在所有页面 前两页除外 的页脚上添加一行纯文本 不是徽标或类似内容 有谁有一个如何做到这一点的例子 用任何语言 Update 原始 PDF 是用 Scribus 制作的 我可以完全控制它 因此 如果更容易进行查
  • 如何开始 Zend Framework 开发

    Hai 首先谢谢 我下载了 Zend 框架 C wamp zend 我将 php ini 的包含路径更改为 C wamp zend 我在我的 php 信息中看到了这个 我认为包含路径是正确的 我仍然有很多疑问 我从哪里开始在 zend 框架
  • 为什么未到达的 try-catch 块会增加运行时间?

    我目前正在创建自己的容器库 但我已经看到无法访问 if 语句无效 try catch阻止增加运行时间 这是我的测试 Vector cpp template
  • Cocoapods 框架不支持配置文件

    我是 iOS 开发领域的新手 我正在从事 iOS 应用程序开发工作 我正在使用 Cocoapods 集成 Alamofire 和 KeychainSwift 等第三方库 当我导出存档以从本地生成 ipa 文件时 它工作正常 但是当我尝试在
  • onClick 事件适用于触摸屏设备上的触摸吗?

    我用过onclick我的网站上的活动 但是 当我在谷歌浏览器的开发人员模式移动视图中打开它时 触摸使用鼠标单击的元素没有任何反应 所以我的问题是 我还必须添加吗ontouch事件连同onclick事件或 onClick 事件适用于所有触摸屏
  • 错误:意外的标记:punc ()

    我正在尝试构建使用 webpack 的项目 我的 UglifyJS 选项如下所示 new UglifyJSPlugin sourceMap false uglifyOptions compress warnings false output
  • 处理不兼容的字符编码:UTF-8 和 ASCII-8BIT

    我在生产中遇到不兼容的字符编码错误 我尝试在本地重现它 但没有成功 这是错误消息 A ActionView Template Error occurred in controller name action name incompatibl
  • 使用 Xcode 为 OS X Lion / Mountain Lion 编译 OpenCV (2.3.1+)

    谁能给我提供一些如何使用 Xcode 在 OS X Lion 上编译 OpenCV 2 3 1 的详细指南 我对此很生气 我得到了源代码 使用 cmake 创建 Xcode 模板并尝试构建它 但它失败并出现大约 200 个错误 提前致谢 多
  • 当 ValidationRules 无法共享时,在 DataTemplates 中重新使用绑定实例

    我正在寻找解决方案和 或为什么在 DataTemplate 中共享 Binding 实例背后的合理性 这最终归结为这样一个事实 在 DataTemplate 中 似乎没有办法为生成的每个控件强制在 DependencyProperty 上绑
  • 有哪些 x86 指令会对 ESP 产生副作用?

    我知道call and ret将修改的值esp然后push and pop有很多变体 但是还有其他指令会影响堆栈指针吗 The following instructions modify the stack pointer as an im
  • 打开下拉菜单时防止 select2 自动聚焦其搜索输入

    我正在寻找一种方法来防止 select2 的搜索输入在打开 select2 下拉菜单时自动聚焦 我知道这是 select2 的预期默认行为 虽然这对于桌面客户端来说很好 但我需要阻止 iPad 上的这种行为 因为它会触发 iPad 软件键盘
  • Xamarin Forms:单击重新启动按钮时网格按钮 UI 中断

    我正在使用一个button在 的里面grid用于显示字母以实施Word search game 最初 用户界面看起来不错 但是当单击play again按钮 UI 中断 截屏 网格内设置按钮的代码 void SetGridLayout ch
  • 选择多个模式的 awk 代码

    这是我的输入文件 比如modified txt r4544 n479826 2012 08 28 07 12 33 0400 Tue 28 Aug 2012 1 line Changed paths M branches 8 6 0 con
  • 如何在R中将plot转换为ggplot?

    我是 R 新手 我正在尝试将绘图转换为 ggplot plot res s type n main title print lines res s res s output 2014 02 14 51 8460 2014 02 14 44
  • 如何在 Spring-Data-JPA Repository 中重用参数?

    在看着查询创建 http docs spring io spring data jpa docs current reference html repositories query methods query creation对于 Spri
  • Firefox 和 Chrome 为 offsetTop 提供了不同的值

    我试图相对于输入字段定位一个跨度元素 让我们称之为 工具提示跨度 为此 我将工具提示跨度和输入字段包装在另一个跨度元素中 我们称之为 包装器跨度 该元素具有position relative 然后我设置position absolute在工
  • sklearn 中组件解释的偏最小二乘方差

    我正在尝试使用 sklearn 中的代码执行 PLSRegression 并且我想保留那些解释一定程度方差的组件 例如 PCA 中的组件 有没有办法知道 PLS 中每个分量解释了多少方差 我也有计算每个组件的解释方差的相同要求 我是 PLS
  • 将 Web API 添加到 asp.net MVC 项目时出现问题(追溯)

    我正在 Visual Studio 2013 中使用 asp net mvc 迈出第一步 但遇到了一个奇怪的问题 我以 MVC 的形式启动了我的项目 并且没有选中 Web API 框来包含核心参考 不过现在我想使用 Web API 功能 我
  • 多线程写入文件

    前几天刚开始使用 python 对多线程的整个概念还很陌生 我在多线程时写入文件时遇到问题 如果我按照常规方式执行此操作 它会不断覆盖正在写入的内容 使用 5 个线程写入文件的正确方法是什么 不降低性能的最佳方法是在所有线程之间使用队列 每
  • 为什么必须通过 this 指针访问模板基类成员?

    如果下面的类不是模板 我可以简单地拥有x in the derived班级 但是 通过下面的代码 我have to use this gt x Why template