在编译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 bug,因为它does not compile with clang .
@n.m.举了一个the required code for template keyword,@dyp improved it的例子 . @n.m.也使用SFINAE写了the another code for both keywords .
@James Kanze在他的回答中认为,编写所需的代码是不可能的,任何尝试这样做都会导致未定义的行为 . 所以上面的代码示例是非法的 .
It is interesting to find out who is right and what the C++ standard says about this.
2 回答
规则是:只要依赖于模板参数的名称是类型,就必须使用
typename
. 考虑到有需要的明显案例这里,第二个
typename
用于指示type
是class T
中定义的类型 . 因此,p
是指向T::type
类型的指针 .如果没有
typename
,type
将被视为class T
的成员 . 所以表达式:将
class T
的type
成员与p
相乘 .同样,规则是:在访问使用模板参数的模板成员时,必须使用
.template
,->template
或::template
. 考虑:在不使用
template
的情况下,编译器不知道<
令牌不小于但不是模板参数列表的开头 .根据定义,无论是否有关键字,都不可能编写含义不同的代码;任何这样做的尝试都会导致未定义的行为 . 这些关键字的唯一目的(至少在此上下文中)是允许编译器在实例化之前完全解析模板:为了正确解析C,编译器必须知道符号是指定类型,模板还是其他东西 .
实例化模板后,编译器不再需要关键字;它们对名称查找或其他任何内容都没有影响 . 唯一的特殊之处在于,如果找到的名称对您的声明(您说的类型,并且在实例化中,它不是类型)存在谎言,则会发生未定义的行为 . 例如,如果编译器以解析树的形式存储了模板,则此解析树将不正确,并且谁知道这可能意味着什么 .
我希望大多数优秀的编译器会在第一个解析中注明该类别,如果名称查找返回其他内容,则会发出错误,但由于历史原因,我怀疑仍有编译器或多或少忽略
template
或typename
在此背景下,将其视为评论;将模板存储为标记序列,并且只有在实例化模板后才使用实例在实例化中找到的类别进行解析 .编辑:
我一直在重读部分标准,我不再确定是否存在未定义的行为 . C 11,至少说:
通常(但并非总是)形成错误需要诊断 . (如上所述,我希望编译器在任何情况下都能发出诊断信息 . )