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

2024-04-23

在模板中,我必须在哪里以及为什么要放置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”关键字? 的相关文章

  • 检查两个数是否是彼此的排列?

    给定两个数字 a b 使得 1 例如 123 是 312 的有效排列 我也不想对数字中的数字进行排序 如果您指的是数字的字符 例如 1927 和 9721 则 至少 有几种方法 如果允许排序 一种方法是简单地sprintf将它们放入两个缓冲
  • 如何检查图像对象与资源中的图像对象是否相同?

    所以我试图创建一个简单的程序 只需在单击图片框中更改图片即可 我目前只使用两张图片 所以我的图片框单击事件函数的代码 看起来像这样 private void pictureBox1 Click object sender EventArgs
  • 访问私人成员[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 通过将类的私有成员转换为 void 指针 然后转换为结构来访问类的私有成员是否合适 我认为我无权修改包含我需要访问的数据成员的类 如果不道德 我
  • 从父类调用子类方法

    a doStuff 方法是否可以在不编辑 A 类的情况下打印 B did stuff 如果是这样 我该怎么做 class Program static void Main string args A a new A B b new B a
  • 未解决的包含:“cocos2d.h” - Cocos2dx

    当我在 Eclipse 中导入 cocos2dx android 项目时 我的头文件上收到此警告 Unresolved inclusion cocos2d h 为什么是这样 它实际上困扰着我 该项目可以正确编译并运行 但我希望这种情况消失
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • 将布尔参数传递给 SQL Server 存储过程

    我早些时候问过这个问题 我以为我找到了问题所在 但我没有 我在将布尔参数传递给存储过程时遇到问题 这是我的 C 代码 public bool upload false protected void showDate object sende
  • 指针问题(仅在发布版本中)

    不确定如何描述这一点 但我在这里 由于某种原因 当尝试创建我的游戏的发布版本进行测试时 它的敌人创建方面不起作用 Enemies e level1 3 e level1 0 Enemies sdlLib 500 2 3 128 250 32
  • 如何将图像和 POST 数据上传到 Azure 移动服务 ApiController 终结点?

    我正在尝试上传图片and POST表单数据 尽管理想情况下我希望它是json 到我的端点Azure 移动服务应用 我有ApiController method HttpPost Route api upload databaseId sea
  • 将目录压缩为单个文件的方法有哪些

    不知道怎么问 所以我会解释一下情况 我需要存储一些压缩文件 最初的想法是创建一个文件夹并存储所需数量的压缩文件 并创建一个文件来保存有关每个压缩文件的数据 但是 我不被允许创建许多文件 只能有一个 我决定创建一个压缩文件 其中包含有关进一步
  • C 预处理器库

    我的任务是开发源分析工具C程序 并且我需要在分析本身之前预处理代码 我想知道什么是最好的图书馆 我需要一些重量轻 便于携带的东西 与其推出自己的 为什么不使用cpp这是的一部分gcc suite http gcc gnu org onlin
  • Cython 和类的构造函数

    我对 Cython 使用默认构造函数有疑问 我的 C 类 Node 如下 Node h class Node public Node std cerr lt lt calling no arg constructor lt lt std e
  • Qt moc 在头文件中实现?

    是否可以告诉 Qt MOC 我想声明该类并在单个文件中实现它 而不是将它们拆分为 h 和 cpp 文件 如果要在 cpp 文件中声明并实现 QObject 子类 则必须手动包含 moc 文件 例如 文件main cpp struct Sub
  • 将自定义元数据添加到 jpeg 文件

    我正在开发一个图像处理项目 C 我需要在处理完成后将自定义元数据写入 jpeg 文件 我怎样才能做到这一点 有没有可用的图书馆可以做到这一点 如果您正在谈论 EXIF 元数据 您可能需要查看exiv2 http www exiv2 org
  • for循环中计数器变量的范围是多少?

    我在 Visual Studio 2008 中收到以下错误 Error 1 A local variable named i cannot be declared in this scope because it would give a
  • 插入记录后如何从SQL Server获取Identity值

    我在数据库中添加一条记录identity价值 我想在插入后获取身份值 我不想通过存储过程来做到这一点 这是我的代码 SQLString INSERT INTO myTable SQLString Cal1 Cal2 Cal3 Cal4 SQ
  • C++ fmt 库,仅使用格式说明符格式化单个参数

    使用 C fmt 库 并给定一个裸格式说明符 有没有办法使用它来格式化单个参数 example std string str magic format 2f 1 23 current method template
  • WCF:将随机数添加到 UsernameToken

    我正在尝试连接到用 Java 编写的 Web 服务 但有些东西我无法弄清楚 使用 WCF 和 customBinding 几乎一切似乎都很好 除了 SOAP 消息的一部分 因为它缺少 Nonce 和 Created 部分节点 显然我错过了一
  • 为什么我收到“找不到编译动态表达式所需的一种或多种类型。”?

    我有一个已更新的项目 NET 3 5 MVC v2 到 NET 4 0 MVC v3 当我尝试使用或设置时编译出现错误 ViewBag Title财产 找不到编译动态表达式所需的一种或多种类型 您是否缺少对 Microsoft CSharp
  • 使用 libcurl 检查 SFTP 站点上是否存在文件

    我使用 C 和 libcurl 进行 SFTP FTPS 传输 在上传文件之前 我需要检查文件是否存在而不实际下载它 如果该文件不存在 我会遇到以下问题 set up curlhandle for the public private ke

随机推荐