"typename"和"template"关键词:它们真的有必要吗?
"typename" and "template" keywords: are they really necessary?
这个网站上有很多关于编译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.给出了 @@n.m.@James Kanze在他的回答中认为,编写所需的代码是不可能的,任何尝试都会导致未定义的行为。因此,上面的代码示例是非法的。 找出谁是对的以及C++标准对此有何评价是很有趣的template
关键字所需代码的示例,@dyp对其进行了改进。
规则是:只要依赖于模板参数的名称是类型,就必须使用typename
。有需要的明确情况,请考虑
template <typename T>
class Foo {
typename T::type * p;
//...
};
这里,第二typename
用于指示type
是在class T
内定义的类型。因此,p
是指向类型T::type
的指针。
如果没有typename
,type
将被视为class T
的成员。因此表达式:
T::type * p
将是CCD_ 17的CCD_ 16成员与CCD_。
类似地,规则是:访问使用模板参数的模板成员时,必须使用.template
、->template
或::template
。考虑:
p->template SomeMethod<int>(x);
如果不使用template
,编译器不知道<
令牌不是小于,而是模板参数列表的开始。
根据定义,不可能编写与有或没有关键字的意思;任何这样做的尝试都会导致未定义的行为。这些的唯一目的关键字(至少在本文中)允许编译器在实例化之前完全解析模板:为了正确解析C++,编译器必须知道符号指定类型、模板或其他东西。
一旦实例化了模板,编译器就不再真正需要关键字;它们对名称查找没有影响,或者其他任何东西。唯一的特殊性是,如果在你的声明中撒谎(你说键入,然后在实例化,它不是一种类型),则会发生未定义的行为。如果例如,编译器已将模板存储为一个解析树,这个解析树是不正确的,谁知道呢这可能意味着什么。
我希望大多数优秀的编译器都会注意到这一类别在第一次解析中,如果名称查找返回其他内容,发出错误,但由于历史原因,我怀疑仍然是或多或少忽略template
或typename
,将其视为评论;存储模板作为令牌序列,并且只解析一次模板被实例化,使用它实际找到的类别在实例化中。
编辑:
我一直在重读标准的部分内容,现在我不再确保存在未定义的行为。至少C++11说:
模板声明或定义中使用的名称依赖于模板的参数被假定为不命名类型除非适用的名称查找找到类型名称或名称是合格的。"按关键字typename。
当限定的id旨在引用不是当前实例化的成员及其嵌套的名称说明符引用依赖类型,它应该是前缀为关键字typename,形成类型名说明符。如果中的合格idtypename说明符不表示类型,程序是不正规。
格式错误通常(但并非总是)需要诊断。(作为如上所述,我希望编译器发出诊断无论如何。)
- 在决定是通过参考还是通过价值时,尺寸真的是一个问题吗
- 为什么返回类型中需要typename?C++
- 字节真的是最小可寻址单元吗
- 如果我真的真的想从 STL 容器继承,并且我继承构造函数并删除新运算符,会发生什么?
- 如何在 std::vector 中找到<bool>哪些索引是真的?
- std::string 的对象真的可以移动吗?
- 在这种情况下,我真的复制了字节还是复制了字符?
- C++ assigment std::list:<typename>:itrator 在 main 中工作,但在方法中它不起作用
- 使用 'typename' 关键字将非类型视为依赖上下文中的类型
- int8_t和uint8_t真的是整数吗?它们有什么用?
- 真的没有来自 std::string_view 的 std::string 的显式构造函数吗?
- 查找不等式为真的次数时出现问题
- 考虑到其他好处,关键字'auto'真的有助于简化调试C++吗?
- 有没有更好的方法来处理异常? try-catch块真的很丑
- 在为嵌套类定义行外友元时,我真的必须打破封装吗?
- 你如何理解"std: :forward is just syntactic sugar"?这是真的吗?
- "std::forward"和"std::move"真的不生成代码吗?
- 在"template"和函数声明之间使用:template<typename trait> using tr = base_trait<trait> void fn(tr::t
- VS 2017 和 2019 运行 c++ 真的很慢
- "typename"和"template"关键词:它们真的有必要吗?