在编译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写了一个很好的答案,但它更适合问题"Where and why do I have to put the “template” and “typename” keywords?",而不是我的问题。
@Simple举了一个the required code for typename
keyword和its possible variation的例子。 @Jarod42提供了another variation without any templates,这可能是 gcc 错误,因为它does not compile with clang。
@n.m.举了一个the required code for template
keyword,@dyp improved it的例子。 @n.m.还使用the another code for both keywords撰写了SFINAE。
@James Kanze在他的回答中指出,编写所需的代码是不可能的,任何尝试这样做都会导致未定义的行为。因此上面的代码示例是非法的。
有趣的是找出谁是对的以及C ++标准对此有何看法。
答案 0 :(得分:6)
规则是:只要依赖于模板参数的名称是类型,就会使用typename
。 是明确需要的情况,请考虑
template <typename T>
class Foo {
typename T::type * p;
//...
};
此处,第二个typename
用于表示type
是class T
中定义的类型。因此,p
是指向T::type
类型的指针。
如果没有typename
,type
将被视为class T
的成员。所以表达式:
T::type * p
是type
class T
成员与p
的乘法。
同样,规则是:.template
,->template
或::template
在访问使用模板参数的模板成员时必须。考虑:
p->template SomeMethod<int>(x);
不使用template
,编译器不知道<
令牌不是小于,而是模板参数列表的开头< / em>的
答案 1 :(得分:2)
根据定义,不可能编写不同的代码 含有或没有关键字的含义;任何这样做的企图都会 导致未定义的行为。这些的唯一目的 关键字(至少在此上下文中)是允许编译器 在实例化之前完全解析模板:为了 正确解析C ++,编译器必须知道是否有符号 指定类型,模板或其他东西。
实例化模板后,编译器就不再真了 需要关键词;它们对名称查找没有影响,或者 还要别的吗。唯一的特点是,如果找到名称 骗你的声明(你说的类型,并在 实例化,它不是类型),发生未定义的行为。如果, 例如,编译器以模板的形式存储了模板 一个解析树,这个解析树将是不正确的,谁知道 这可能意味着什么。
我希望大多数好的编译器会注意到这个类别
在第一个解析中,如果名称查找返回其他内容,
发出错误,但由于历史原因,我怀疑那里
仍然是编译器或多或少忽略template
或。{
typename
在这种情况下,将其视为评论;存储
模板作为一系列标记,只解析一次
使用实际找到的类别实例化模板
在实例化中。
编辑:
我一直在重读部分标准,而我已经不在了 确定存在未定义的行为。至少C ++ 11说:
模板声明或定义中使用的名称,即 假定依赖于模板参数不命名类型 除非适用的名称查找找到类型名称或名称 是合格的。“通过关键字typename。
当qualified-id旨在引用不是的类型时 当前实例化的成员及其成员 nested-name-specifier指的是一个依赖类型,它应该是 以关键字typename为前缀,形成 typename-specifier。如果是qualified-id typename-specifier不表示类型,程序是 不良形成。
通常(但并非总是)形成错误需要诊断。 (如 如上所述,我希望编译器能够发出诊断信息 在任何情况下。)