"typename"和"template"关键词:它们真的有必要吗?

"typename" and "template" keywords: are they really necessary?

本文关键字:真的 typename template 关键词      更新时间:2023-10-16

这个网站上有很多关于编译c++模板代码的问题。这类问题最常见的解决方案之一是在程序代码的正确位置添加typename(以及不太常见的template)关键字:

template<typename T>
class Base
{
public:
typedef char SomeType;
template<typename U>
void SomeMethod(SomeType& v)
{
// ...
}
};
template<typename T>
class Derived : public Base<T>
{
public:
void Method()
{
typename Base<T>::SomeType x;
//  ^^^^^^^^
this->template SomeMethod<int>(x);
//        ^^^^^^^^
}
};

是否有一个代码在编译时同时使用和不使用关键字typename,并给出不同的结果(例如输出字符串)?template关键字的类似问题。

如果没有,这些关键词在这样的意义上是否真的有必要?

当前形势的小概述

@Paul Evans写了一个很好的答案,但它更适合"我必须把"模板"answers"typename"关键字放在哪里以及为什么?"这个问题,而不是我的问题。

@Simple给出了typename关键字所需代码及其可能的变体的示例@Jarod42给出了另一个没有任何模板的变体,这可能是一个gcc错误,因为它不使用clang编译。

@n.m.给出了template关键字所需代码的示例,@dyp对其进行了改进。

@@n.m.@James Kanze在他的回答中认为,编写所需的代码是不可能的,任何尝试都会导致未定义的行为。因此,上面的代码示例是非法的。

找出谁是对的以及C++标准对此有何评价是很有趣的

规则是:只要依赖于模板参数的名称是类型,就必须使用typename需要的明确情况,请考虑

template <typename T> 
class Foo { 
typename T::type * p; 
//... 
}; 

这里,第二typename用于指示type是在class T内定义的类型。因此,p是指向类型T::type的指针。

如果没有typenametype将被视为class T的成员。因此表达式:

T::type * p

将是CCD_ 17的CCD_ 16成员与CCD_。

类似地,规则是:访问使用模板参数的模板成员时,必须使用.template->template::template。考虑:

p->template SomeMethod<int>(x);

如果不使用template,编译器不知道<令牌不是小于,而是模板参数列表的开始

根据定义,不可能编写与有或没有关键字的意思;任何这样做的尝试都会导致未定义的行为。这些的唯一目的关键字(至少在本文中)允许编译器在实例化之前完全解析模板:为了正确解析C++,编译器必须知道符号指定类型、模板或其他东西。

一旦实例化了模板,编译器就不再真正需要关键字;它们对名称查找没有影响,或者其他任何东西。唯一的特殊性是,如果在你的声明中撒谎(你说键入,然后在实例化,它不是一种类型),则会发生未定义的行为。如果例如,编译器已将模板存储为一个解析树,这个解析树是不正确的,谁知道呢这可能意味着什么。

我希望大多数优秀的编译器都会注意到这一类别在第一次解析中,如果名称查找返回其他内容,发出错误,但由于历史原因,我怀疑仍然是或多或少忽略templatetypename,将其视为评论;存储模板作为令牌序列,并且只解析一次模板被实例化,使用它实际找到的类别在实例化中。

编辑:

我一直在重读标准的部分内容,现在我不再确保存在未定义的行为。至少C++11说:

模板声明或定义中使用的名称依赖于模板的参数被假定为不命名类型除非适用的名称查找找到类型名称或名称是合格的。"按关键字typename。

当限定的id旨在引用不是当前实例化的成员及其嵌套的名称说明符引用依赖类型,它应该是前缀为关键字typename,形成类型名说明符。如果中的合格idtypename说明符不表示类型,程序是不正规。

格式错误通常(但并非总是)需要诊断。(作为如上所述,我希望编译器发出诊断无论如何。)