“typename”和“template”关键字:他们真的有必要吗?

时间:2014-02-27 13:19:08

标签: c++ templates c++11 keyword typename

在编译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 keywordits 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 ++标准对此有何看法。

2 个答案:

答案 0 :(得分:6)

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

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

此处,第二个typename用于表示typeclass T中定义的类型。因此,p是指向T::type类型的指针。

如果没有typenametype将被视为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不表示类型,程序是   不良形成。

通常(但并非总是)形成错误需要诊断。 (如 如上所述,我希望编译器能够发出诊断信息 在任何情况下。)