zoukankan      html  css  js  c++  java
  • Effective C++ 笔记 —— Item 42: Understand the two meanings of typename.

    Question: what is the difference between class and typename in the following template declarations?

    template<class T> class Widget; // uses "class"
    template<typename T> class Widget; // uses "typename"

    Answer: nothing. When declaring a template type parameter, class and typename mean exactly the same thing.

    C++ doesn‘t always view class and typename as equivalent, however. Sometimes you must use typename.

    Suppose we have a template for a function:

    template<typename C> // print 2nd element in container;
    void print2nd(const C& container) 
    { 
        // this is not valid C++!
        if (container.size() >= 2) 
        {
            C::const_iterator iter(container.begin()); // get iterator to 1st element
            ++iter; // move iter to 2nd element
            int value = *iter; // copy that element to an int
            std::cout << value; // print the int
        }
    }

    To rectify the situation, we have to tell C++ that C::const_iterator is a type. We do that by putting typename immediately in front of it:

    template<typename C> // this is valid C++
    void print2nd(const C& container)
    {
        if (container.size() >= 2) 
        {
            typename C::const_iterator iter(container.begin());
            // ...
        }
    }

    The general rule is simple: anytime you refer to a nested dependent type name in a template, you must immediately precede it by the word typename. (Again, I'll describe an exception shortly.)

    typename should be used to identify only nested dependent type names; other names shouldn't have it. For example, here's a function template that takes both a container and an iterator into that container:

    template<typename C> // typename allowed (as is "class")
    void f(const C& container, // typename not allowed
    typename C::iterator iter); // typename required

    The exception to the "typename must precede nested dependent type names" rule is that typename must not precede nested dependent type names in a list of base classes or as a base class identifier in a member initialization list. For example:

    template<typename T>
    class Derived : public Base<T>::Nested // base class list: typename not allowed
    { 
        
    public:
        explicit Derived(int x)
            : Base<T>::Nested(x) // base class identifier in mem. init. list: typename not allowed
        { 
            typename Base<T>::Nested temp; // use of nested dependent type name not in a base class list or as a base class identifier in a mem. init. list: typename
            //...
        }
    };

    Let's look at one last typename example,

    template<typename IterT>
    void workWithIterator(IterT iter)
    {
        typename std::iterator_traits<IterT>::value_type temp(*iter);
        // ...
    }

     Because std::iterator_traits::value_type is a nested dependent type name (value_type is nested inside iterator_traits, and IterT is a template parameter), we must precede it by typename.

    Things to Remember:

    • When declaring template parameters, class and typename are inter-changeable.
    • Use typename to identify nested dependent type names, except in base class lists or as a base class identifier in a member initialization list. 
  • 相关阅读:
    javaScript 基础知识汇总(六)
    javaScript 基础知识汇总(五)
    javaScript 基础知识汇总(四)
    WPF — Grid布局中行的高度和列的高度值定义的三种形式
    C# — 用递归实现斐波拉契数列的第n项
    C# — ref参数、params参数、out参数详解
    Android apk反编译教程
    WPF学习资源
    C# — 通过点击回车执行任务
    C# — MvvMLight框架入门资源
  • 原文地址:https://www.cnblogs.com/zoneofmine/p/15670853.html
Copyright © 2011-2022 走看看