我必须在哪里以及为什么必须放置“template”和“typename”关键字?

2024-01-22

在模板中,我必须在哪里以及为什么要放置typename and template关于从属名称?
到底什么是从属名称?

我有以下代码:

template <typename T, typename Tail> // Tail will be a UnionNode too.
struct UnionNode : public Tail {
    // ...
    template<typename U> struct inUnion {
        // Q: where to add typename/template here?
        typedef Tail::inUnion<U> dummy; 
    };
    template< > struct inUnion<T> { };
};
template <typename T> // For the last node Tn.
struct UnionNode<T, void> {
    // ...
    template<typename U> struct inUnion; // intentionally not defined
    template< > struct inUnion<T> { };   // specialization only for T
};

我遇到的问题是typedef Tail::inUnion<U> dummy线。我相当确定inUnion是一个从属名称,VC++ 对此感到窒息是完全正确的。

我也知道我应该能够添加template某处告诉编译器inUnion is a 模板 ID,但具体在哪里呢?那么是否应该假设inUnion是一个类模板,即inUnion<U>命名类型而不是函数?


(See 这里也是我的 C++11 答案 https://stackoverflow.com/a/17579889/4561887)

为了解析 C++ 程序,编译器需要知道某些名称是否是类型。下面的例子表明:

t * f;

这个应该怎么解析呢?对于许多语言,编译器不需要知道名称的含义即可解析并基本上知道一行代码执行什么操作。然而,在 C++ 中,上述内容可能会产生截然不同的解释,具体取决于什么t方法。如果它是类型,那么它将是指针的声明f。但是,如果它不是类型,则它将是乘法。所以 C++ 标准在第 (3/7) 段中说:

有些名称表示类型或模板。一般来说,每当遇到一个名称时,都需要在继续解析包含该名称的程序之前确定该名称是否表示这些实体之一。确定这一点的过程称为名称查找。

编译器如何知道名称是什么t::x指的是,如果t指的是模板类型参数?x可以是可以相乘的 static int 数据成员,也可以同样是可以生成声明的嵌套类或 typedef。如果一个名称具有此属性 - 在知道实际模板参数之前无法查找它 - 那么它被称为附属名称(它“取决于”模板参数)。

您可能建议等待用户实例化模板:

等用户实例化模板后,再去了解其真正含义t::x * f;.

这将有效,并且实际上是标准允许的一种可能的实施方法。这些编译器基本上将模板的文本复制到内部缓冲区中,并且仅当需要实例化时,它们才会解析模板并可能检测定义中的错误。但是,其他实现并没有因为模板作者所犯的错误而困扰模板的用户(可怜的同事!),而是选择尽早检查模板,并在实例化发生之前尽快在定义中给出错误。

因此必须有一种方法告诉编译器某些名称是类型而某些名称不是。

“类型名称”关键字

答案是:We决定编译器应该如何解析它。如果t::x是一个依赖名称,那么我们需要在它前面加上前缀typename告诉编译器以某种方式解析它。标准在 (14.6/2) 中说:

模板声明或定义中使用的且依赖于模板参数的名称是 假设不命名类型,除非适用的名称查找找到类型名称或名称是限定的 通过关键字 typename。

有很多名字typename没有必要,因为编译器可以通过模板定义中的适用名称查找来找出如何解析构造本身 - 例如T *f;, when T是类型模板参数。但对于t::x * f;作为一个声明,它必须写成typename t::x *f;。如果省略关键字并且名称被视为非类型,但当实例化发现它表示类型时,编译器会发出常见的错误消息。有时,错误会在定义时给出:

// t::x is taken as non-type, but as an expression the following misses an
// operator between the two names or a semicolon separating them.
t::x f;

语法允许typename仅在限定名称之前- 因此,人们理所当然地认为,如果不合格的名称这样做的话,那么它们总是会引用类型。

正如介绍性文本所暗示的,表示模板的名称也存在类似的问题。

“模板”关键字

还记得上面最初的引述以及标准如何要求对模板进行特殊处理吗?让我们看下面这个看似无辜的例子:

boost::function< int() > f;

对于人类读者来说,这可能看起来很明显。对于编译器来说并非如此。想象一下以下任意定义boost::function and f:

namespace boost { int function = 0; }
int main() { 
  int f = 0;
  boost::function< int() > f; 
}

这实际上是一个有效的表达!它使用小于运算符进行比较boost::function反对零(int()),然后使用大于运算符来比较结果bool反对f。然而,正如您可能知道的那样,boost::function 在真实生活中 http://www.boost.org/doc/libs/1_54_0/doc/html/function.html是一个模板,因此编译器知道(14.2/3):

名称查找(3.4)发现名称是模板名称后,如果该名称后面跟着

现在我们又回到了同样的问题typename。如果我们在解析代码时还不知道该名称是否是模板怎么办?我们需要插入template紧接在模板名称之前,如指定的14.2/4。这看起来像:

t::template f<int>(); // call a function template

模板名称不仅可以出现在::但也经过了-> or .在类成员访问中。您还需要在那里插入关键字:

this->template f<int>(); // call a function template

依赖关系

对于那些书架上有厚厚的标准语言书籍并且想知道我到底在说什么的人,我将谈谈标准中如何指定这一点。

在模板声明中,某些构造具有不同的含义,具体取决于您用来实例化模板的模板参数:表达式可能具有不同的类型或值,变量可能具有不同的类型,或者函数调用可能最终会调用不同的函数。这种构造通常被认为是depend关于模板参数。

该标准通过构造是否依赖来精确定义规则。它将它们分成逻辑上不同的组:一组捕获类型,另一组捕获表达式。表达式可能取决于它们的值和/或它们的类型。所以我们有,附有典型的例子:

  • 依赖类型(例如:类型模板参数T)
  • 值相关表达式(例如:非类型模板参数N)
  • 类型相关的表达式(例如:转换为类型模板参数(T)0)

大多数规则都是直观的并且是递归构建的:例如,构造为的类型T[N]是一个依赖类型,如果N是一个值相关的表达式或T是依赖类型。详细信息可以阅读部分(14.6.2/1) 对于依赖类型,(14.6.2.2)对于类型相关的表达式和(14.6.2.3)对于值相关的表达式。

从属名称

该标准有点不清楚是什么exactly is a 附属名称。简单阅读一下(你知道,最小惊喜原则),它定义的所有内容都是附属名称是下面函数名称的特殊情况。但既然明确T::x还需要在实例化上下文中查找,它还需要是一个依赖名称(幸运的是,从 C++14 中期开始,委员会已经开始研究如何修复这个令人困惑的定义)。

为了避免这个问题,我对标准文本进行了简单的解释。在表示依赖类型或表达式的所有构造中,其中的一个子集表示名称。因此,这些名称是“从属名称”。名称可以采用不同的形式 - 标准规定:

名称是表示实体或标签(6.6.4, 6.1)

标识符只是一个简单的字符/数字序列,而接下来的两个是operator + and operator type形式。最后的形式是template-name <argument list>。所有这些都是名称,并且按照标准中的常规使用,名称还可以包含限定符,说明名称应该在哪个名称空间或类中查找。

值依赖表达式1 + N不是一个名字,但是N是。所有依赖结构(名称)的子集称为附属名称。然而,函数名称在模板的不同实例化中可能具有不同的含义,但不幸的是,不符合这个一般规则。

依赖函数名称

这不是本文主要关注的问题,但仍然值得一提:函数名称是单独处理的异常。标识符函数名称不依赖于其本身,而是依赖于调用中使用的类型相关参数表达式。在示例中f((T)0), f是一个从属名称。在标准中,这被指定为(14.6.2/1).

附加注释和示例

在足够多的情况下,我们都需要typename and template。您的代码应如下所示

template <typename T, typename Tail>
struct UnionNode : public Tail {
    // ...
    template<typename U> struct inUnion {
        typedef typename Tail::template inUnion<U> dummy;
    };
    // ...
};

关键词template并不总是必须出现在名称的最后部分。它可以出现在用作范围的类名之前的中间,如下例所示

typename t::template iterator<int>::value_type v;

在某些情况下,关键字是被禁止的,详情如下

  • 不允许在依赖基类的名称上写typename。假定给定的名称是类类型名称。对于基类列表和构造函数初始值设定项列表中的名称都是如此:

     template <typename T>
     struct derive_from_Has_type : /* typename */ SomeBase<T>::type 
     { };
    
  • 在 using 声明中,不可能使用template最后一次之后::,以及 C++ 委员会said http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#109不致力于解决方案。

     template <typename T>
     struct derive_from_Has_type : SomeBase<T> {
        using SomeBase<T>::template type; // error
        using typename SomeBase<T>::type; // typename *is* allowed
     };
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我必须在哪里以及为什么必须放置“template”和“typename”关键字? 的相关文章

  • C# 测试活动的互联网连接。 Ping google.com

    C 2008 我正在使用此代码来测试互联网连接 因为我的应用程序必须登录到网络服务器 但是 如果用户互联网连接失败或电缆被拔出 我必须通知用户 Ping www google com to check if the user has a i
  • 在 C# 中轻松创建支持索引的属性

    在 C 中我发现索引属性 http msdn microsoft com en us library aa288464 VS 71 aspx非常有用 例如 var myObj new MyClass myObj 42 hello Conso
  • C++ 和序列化:有什么方法可以进行某种内省吗?

    我读过一些例子维基百科 http en wikipedia org wiki Type introspection C 2B 2B但我正在寻找一些现实生活中的例子 如何使用内省 为什么 它有助于编写干净的代码 以及代码本身 例如 有没有办法
  • 可变数量的(常量)引用参数

    我试图从我的高级代码 使用 C 11 中消除原始指针 并且我找到了引用 尤其是const 在许多情况下 当没有所有权转移时 是一个很好的替代品 但如果有的话该怎么办variable我想通过 常量 引用传递的参数数量 你不能创建一个std v
  • C# 并行与并行线程代码性能

    我一直在测试 System Threading Parallel 与线程的性能 我很惊讶地发现并行比线程花费更长的时间来完成任务 我确信这是由于我对并行的了解有限 我刚刚开始阅读 我想我会分享一些片段 如果有人可以向我指出并行代码比线程代码
  • WPF Dispatchertimer 延迟反应/冻结

    在我的 WPF 应用程序中 我使用 3 个不同的 DispatcherTimers 一种是用于显示当前时间 一种是每 5 秒运行一次数据库查询 第三个每 1 秒刷新一次自定义按钮的值 当我的程序运行时 有很多延迟 冻结 例如 时间开始正确计
  • 增量决策树 C++ 实现

    有谁知道决策树分类器的增量实现吗 这样 当您将新实例添加到训练集中时 它可以根据现有决策树分类器以低计算量并尽可能快地生成最佳决策树分类器 换句话说 我有一个最优决策树分类器集A 其中命名为T 1 现在我想添加实例X to set A并找到
  • 在目标 VS 安装时,VSIX 扩展内部使用的 WPF-Log4Net 未输出日志

    当 Log4net 在 VSIX 扩展中使用并安装在另一个目标 VS 上时 它不会记录日志 我有一个 WPF 解决方案 我下载了 log4net dll 添加了 log4net config 并将 复制到输出目录 值设置为 始终复制 log
  • 为什么将 char 传递给函数会改变它在 c 中的值?

    我目前正在关注本作业簿 http www cs bham ac uk exr lectures opsys 10 11 lectures os dev pdf关于构建操作系统 我的目的是写一个64位内核 我已经在文本模式下加载 内核 代码并
  • 修剪 UIImage 边框

    这是我想要修剪的图像的示例 我想去掉图像周围的边框 在本例中是顶部和底部的黑条 我在Github上找到了一个库 CKImageAdditions https github com cmkilger CKImageAdditions 但是它似
  • 函数指针上的未知类型 F TYPE

    include
  • ASP.NET中如何访问除wwwroot以外的位置

    我可以使用访问服务器的物理位置Server MapPath 这给了我内部的物理路径wwwroot文件夹 我想将一些数据保存到同一服务器的另一个驱动器中D 驾驶 我想我无法获取以下位置的物理位置D 驾驶使用Server MapPath因为它位
  • 如何从Web JavaScript应用程序获取桌面C#程序中的变量

    我遇到一个问题 有两个应用程序 一种是 C 中的桌面应用程序 另一种是 javascript 中的 Web 应用程序 运行桌面应用程序中的一些变量或信息需要传输到Web应用程序 有谁知道如何解决这个问题 有人愿意提供更多细节来解决这个问题吗
  • C++:LPWSTR 在 cout 中打印为地址

    我有一个类型变量LPTSTR 我打印到std cout with lt lt 在 ANSI 系统中 不知道它是在哪里确定的 它工作得很好 它打印了字符串 现在 在 Unicode 系统中 我得到的是十六进制地址而不是字符串 那么 为什么LP
  • C++ 联合数组和变量?

    在C 中没有办法做这样的事情吗 union Scalar x y Scalar v 2 Where x v 0 and y v 1 既然您使用的是 C 而不是 C 并且它们具有相同的类型 为什么不直接将 x 设为对 v 0 的引用 将 y
  • 在Framework 4.6项目中使用.net core DLL

    我已经在 net core 2 0 中构建了一个 DLL 现在我想在使用 net 4 6 1 框架的 WinForms 项目中使用它 我可以引用该 dll 但收到 System IO FileLoadException 表示找不到 Syst
  • 是否可以编写一个在另一个 Windows 应用程序中选择文本时收到通知的 Windows 应用程序?

    我很好奇是否可以编写一个程序来监视我的文本选择 一种可能的用途是编写一个与编辑器 IDE 无关的代码格式化程序 应用程序 服务 P 启动并以某种方式挂接到窗口中 以便在任何窗口中选择文本时收到通知 启动其他一些应用程序 A 用户选择 A 中
  • char[length]初始化并处理

    我定义了一个字符数组 char d 6 如果我在以下方面有误 请纠正我 此时没有为变量分配内存d 现在我要初始化它 d aaaaa 这种初始化之后 就不需要释放内存了 它将自动完成 我怎么知道是否char 被初始化了吗 我正在寻找类似的模式
  • “显式”关键字对返回值优化 (RVO) 有何影响?

    以下代码工作得很好 显示 RVO struct A A int cout lt lt A A n constructor A const A cout lt lt A A const A n copy constructor A foo r
  • DataGridView 捕获用户行选择

    我在处理选择时遇到问题DataGridView 我的网格视图包含一个金额列 表单上有一个文本框 应显示所选网格视图行的总数 因此 我需要在用户选择 取消选择 gridview 行时捕获事件并相应地计算 添加 减去 金额 我找到了两种方法 使

随机推荐

  • 如何静态断言指针转换是微不足道的?

    假设我有以下类型 struct A int a struct B int b struct C public A public B int c A C 指针可以转换为A 指针根本不调整实际地址 但当C 被投射到B 该值必须改变 我想确保我拥
  • 在 docker 容器内挂载 nfs 共享

    有谁知道如何使用 centos 基础镜像在 docker 容器内挂载 nfs 共享 我试过这个命令 mount server dir mount point 并得到下一个错误 mount nfs rpc statd is not runni
  • 正则表达式:查找没有子串的字符串

    我有一篇大文字 Big piece of text This sentence includes regexp word And this sentence doesn t include that word 我需要找到以 开头的子字符串t
  • 与多个字段和 mongodb 中的 where 条件不同

    我想写一个相当于distinct and where in mongodb SQL查询是select DISTINCT key score from GPC where note test2 and notetwo meet2 id Obj
  • 自定义 iOS Twitter 身份验证页面?

    我正在制作一个移动应用程序 用户可以将他们的 Twitter 帐户连接到该应用程序 我只是有点好奇最好的方法是什么 现在 我希望能够制作自己的自定义页面 无需使用 UIWebView 这可能吗 如果怎样 那么 Thanks 据我了解 您不希
  • 如何在 Node.js server.listen() 中使用可选的主机名参数

    从我到目前为止在教程中读到的内容来看 可选的hostname参数为server listen port hostname backlog callback 一直都是127 0 0 1 环回 0 0 0 0 监听每个可用的网络接口 默认选项
  • Tomcat 中是否可以让一个 appBase 由多个上下文路径提供服务?

    Tomcat 中是否可以让一个 appBase 由多个上下文路径提供服务 我有一个应用程序库 最近替换了第二个应用程序库 我的问题是许多用户仍然访问旧的上下文 我想从单个 appBase 提供现在常见的应用程序 但可以通过任一上下文访问 我
  • Jasmine:可观察到的单元测试 http 服务错误

    我对如何模拟我的 http 服务捕获可观察到的错误感到非常困惑 我已阅读角度文档 但我不明白如何构建测试 我想模拟我的服务中的错误 然后检查它是否捕获了可观察到的错误 我有另一个服务可以创建并抛出可观察到的错误 我的其余服务只是在遇到错误时
  • 我的 MVC 自定义 ControllerFactory 可以工作,但还能更好吗?

    我研究过 Ninject StructureMap 和其他依赖注入和服务定位器框架 但这个问题更多的是关于了解它是如何工作的以及什么可以做得更好 更重要的是 我无意于查看框架的依赖注入源代码 而是了解它在实践 代码中从头到尾是如何实现的 下
  • 如何让 Git 忽略符号链接?

    我的项目文件夹中有符号链接 以便当我在 Windows 10 计算机上的本地开发服务器中运行项目时可以访问大型视频和图像目录 问题是 Git 不允许我执行 add 因为当存在符号链接时 它会给我这个错误 error readlink Pro
  • 您如何向没有 Javascript 之外的编程经验的人解释 Javascript 类型数组?

    最近我经常使用 Canvas 开发一些关于网络游戏的想法 因此 我最近遇到了 Javascript 类型数组 我已经读过一些书 例如MDN https developer mozilla org en US docs Web JavaScr
  • 错误:自构建预编译头以来系统文件已被修改

    我刚刚下载了 xcode 6 的最终版本并编译了一个我正在使用测试版的项目 现在显然生成了以下错误模拟器 有人可以帮助我解决这个问题 fatal error file Applications Xcode app Contents Deve
  • 如何在asp .net core web api中获取后台服务中的主机URL?

    我有一个 Asp Net core Web api 它将运行后台服务来每天安排一些任务并发送一些邮件 在邮件中我需要有 api 的 url 除了控制器之外 还有什么方法可以在后台服务中获取主机 URL 后台服务在 Web 请求的范围之外运行
  • javax.xml.soap.MessageFactory的实例是线程安全的吗?

    有人知道 javax xml soap MessageFactory 的实例是否是线程安全的吗 我找不到任何与之相关的文档 如果您没有看到任何关于某些东西是否是线程安全的文档 您应该假设它不是 如果你假设它是 但事实并非如此 这将避免很多头
  • postgresql 中 mmm yyyy 格式的日期

    我有一个表 其中有一列没有时区的时间戳类型 我想选择该列mmm yyyy格式 例如 2011 年 3 月 怎么格式化成这样呢 我试过 select cast now as date 但它给了我不正确的格式 SELECT TO CHAR NO
  • 用 React 计算 SVG 边界框?

    我正在编写一个使用 React 生成 SVG 的可视化应用程序 我需要的部分之一是标签 即文本 由封闭框包围 带有可变文本 可能会旋转和设置样式 所以我有一个组件NodeLabel 目前具有固定尺寸 render return
  • 使用多列的参数化 IN 子句

    我有一个沿着这些线的查询 我试图通过比较元组来过滤结果集 例如SQL IN 子句中的多列 https stackoverflow com questions 13027708 sql multiple columns in in claus
  • Xcode UI 测试无密码身份验证

    我应该如何测试我的 iPhone 应用程序无密码认证 https medium com ninjudd passwords are obsolete 9ed56d483eb 要注册或登录 Xcode 中的 UI 测试 https devel
  • Solr 到应用程序洞察

    如何配置 Solr 日志以发送到 Azure Application Insights 我看到可以使用 Log4J 附加程序 https learn microsoft com en us azure application insight
  • 我必须在哪里以及为什么必须放置“template”和“typename”关键字?

    在模板中 我必须在哪里以及为什么要放置typename and template关于从属名称 到底什么是从属名称 我有以下代码 template