首页 文章

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

提问于
浏览
4

在编译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 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 回答

  • 6

    规则是:只要依赖于模板参数的名称是类型,就必须使用 typename . 考虑到有需要的明显案例

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

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

    如果没有 typenametype 将被视为 class T 的成员 . 所以表达式:

    T::type * p
    

    class Ttype 成员与 p 相乘 .

    同样,规则是:在访问使用模板参数的模板成员时,必须使用 .template->template::template . 考虑:

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

    在不使用 template 的情况下,编译器不知道 < 令牌不小于但不是模板参数列表的开头 .

  • 2

    根据定义,无论是否有关键字,都不可能编写含义不同的代码;任何这样做的尝试都会导致未定义的行为 . 这些关键字的唯一目的(至少在此上下文中)是允许编译器在实例化之前完全解析模板:为了正确解析C,编译器必须知道符号是指定类型,模板还是其他东西 .

    实例化模板后,编译器不再需要关键字;它们对名称查找或其他任何内容都没有影响 . 唯一的特殊之处在于,如果找到的名称对您的声明(您说的类型,并且在实例化中,它不是类型)存在谎言,则会发生未定义的行为 . 例如,如果编译器以解析树的形式存储了模板,则此解析树将不正确,并且谁知道这可能意味着什么 .

    我希望大多数优秀的编译器会在第一个解析中注明该类别,如果名称查找返回其他内容,则会发出错误,但由于历史原因,我怀疑仍有编译器或多或少忽略 templatetypename 在此背景下,将其视为评论;将模板存储为标记序列,并且只有在实例化模板后才使用实例在实例化中找到的类别进行解析 .

    编辑:

    我一直在重读部分标准,我不再确定是否存在未定义的行为 . C 11,至少说:

    模板声明或定义中使用的名称以及依赖于模板参数的名称,除非适用的名称查找找到类型名称或名称是合格的,否则不会命名类型 . “通过关键字typename . -id旨在引用不是当前实例化成员的类型,并且其嵌套名称说明符引用依赖类型,它应以关键字typename作为前缀,形成typename-specifier . 如果符合条件 - typename-specifier中的id不表示类型,程序格式不正确 .

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

相关问题