• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 297,  comments - 15,  trackbacks - 0

            [Originally written sometime in December, 2006. Fixed a couple markup errors, changed some wording, and added a little bit 12/23/2007. I still don't quite consider it complete; I haven't explained all the rules yet. I have a ranty version of what I want to add here; start reading where it says "[RESUMING]" if you read this document first.]

            The purpose of this document is to describe the reasoning behind the inclusion of the typename keyword in standard C++, and explain where, when, and how it can and can't be used.

            A secondary use

            There is a use of typename that is entirely distinct from the main focus of this discussion. I will present it first because it is easy. It seems to me that someone said "hey, since we're adding typename anyway, why not make it do this" and people said "that's a good idea."

            Most older C++ books, when discussing templates, use the following type of example:

            template <class T> ...

            I know when I was starting to learn templates, at first I was a little thrown by the fact that T was prefaced by class, and yet it was possible to instantiate that template with primitive types such as int. The confusion was very short-lived, but the use of class in that context never seemed to fit entirely right. Fortunately for my sensibilities, it is also possible to use typename:

            template <typename T> ...

            This means exactly the same thing as the previous instance. The typename and class keywords can be used interchangeably to state that a template parameter is a type variable (as opposed to a non-type template parameter).

            I personally like to use typename in this context because I think it's ever so slightly clearer. And maybe not so much "clearer" as just conceptually nicer. (I think that good names for things are very important.) Some C++ programmers share my view, and use typename for templates. (However, later we will see how it's possible that this decision can hurt readibility.) Some programmers make a distinction between templates that are fully generic (such as the STL containers) and more special purpose ones that can only take certain classes, and use typename for the former category and class for the latter. Others use class exclusively. This is just a style choice.

            However, while I use typename in real code, I will stick to class in this document to reduce confusion with the other use of typename.

            The real reason for typename

            This discussion I think follows fairly closely appendix B from the book C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond by David Abrahams and Aleksey Gurtovoy, though I don't have it in front of me now. If there are any deficiencies in my discussion of the issues, that book contains the clearest description of them that I've seen.

            Some definitions

            There are two key concepts needed to understand the description of typename, and they are qualified and dependent names.

            Qualified and unqualified names

            A qualified name is one that specifies a scope. For instance, in the following C++ program, the references to cout and endl are qualified names:

            #include <iostream>

            int main() {
            std::cout %lt;%lt; "Hello world!" %lt;%lt; std:: endl;
            }

            In both cases, the use of cout and endl began with std::.

            Had I decided to bring cout and endl into scope with a using declaration or directive*, they would have been unqualified names, because they would lack the std::.

            (* Remember, a using declaration is like using std::cout;, and actually introduces the name cout into the scope that the using appears in. A using directive is of the form using namespace std; and makes names visible but doesn't introduce anything. [12/23/07 -- I'm not sure this is true. Just a warning.])

            Note, however, that if I had brought them into scope with using but still used std::cout, it remains a qualified name. The qualified-ness of a name has nothing to do with what scope it's used in, what names are visible at that point of the program etc.; it is solely a statement about the name that was used to reference the entity in question. (Also note that there's nothing special about std, or indeed about namespaces at all. vector<int>::iterator is a nested name as well.)

            Dependent and non-dependent names

            A dependent name is a name that depends on a template parameter. Suppose we have the following declaration (not legal C++):

            template <class T>
            class MyClass {
            int i;
            vector<int> vi;
            vector<int>::iterator vitr;

            T t;
            vector<T> vt;
            vector<T>::iterator viter;
            };

            The types of the first three declarations are known at the time of the template declaration. However, the types of the second set of three declarations are not known until the point of instantiation, because they depend on the template parameter T.

            The names T, vector<T>, and vector<T>::iterator are called dependent names, and the types they name are dependent types. The names used in the first three declarations are called non-dependent names, at the types are non-dependent types.

            The final complication in what's considered dependent is that typedefs transfer the quality of being dependent. For instance:

            typedef T another_name_for_T;

            another_name_for_T is still considered a dependent name despite the type variable T from the template declaration not appearing.

            Note: I am not very familiar with the notion of dependent types in the type theory sense, but they are not quite the same thing in any case. My impression is that you could probably argue a C++ template itself is a dependent type in the type-theoretical sense, but the C++ notion of a dependent type is more like the argument to a dependent type in the type-theoretical sense.

            Some other issues of wording

            Note that while there is a notion of a dependent type, there is not a notion of a qualified type. A type can be unqualified in one instance, and qualified the next; the qualification is a property of a particular naming of a type, not of the type itself. (Indeed, when a type is first defined, it is always unqualified.)

            However, it will be useful to refer to a qualified type; what I mean by this is a qualified name that refers to a type. I will switch back to the more precise wording when I talk about the rules of typename.

            The problem

            So now we can consider the following example:

            template <class T>
            void foo() {
            T::iterator * iter;
            ...
            }

            What did the programmer intend this bit of code to do? Probably, what the programmer intended was for there to be a class that defined a nested type called iterator:

            class ContainsAType {
            class iterator { ... }:
            ...
            };

            and for foo to be called with an instantiation of T being that type:

            foo<ContainsAType>();

            In that case, then line 3 would be a declaration of a variable called iter that would be a pointer to an object of type T::iterator (in the case of ContainsAType, int*, making iter a double-indirection pointer to an int). So far so good.

            However, what the programmer didn't expect is for someone else to come up and declare the following class:

            class ContainsAValue {
            static int iterator;
            };

            and call foo instantiated with it:

            foo<ContainsAValue>();

            In this case, line 3 becomes a statement that evaluates an expression which is the product of two things: a variable called iter (which may be undeclared or may be a name of a global) and the static variable T::iterator.

            Uh oh! The same series of tokens can be parsed in two entirely different ways, and there's no way to disambiguate them until instantiation. C++ frowns on this situation. Rather than delaying interpretation of the tokens until instantiation, they change the languge:

            Before a qualified dependent type, you need typename

            To be legal, assuming the programmer intended line 3 as a declaration, they would have to write

            template <class T>
            void foo() {
            typename T::iterator * iter;
            ...
            }

            Without typename, there is a C++ parsing rule that says that qualified dependent names should be parsed as non-types even if it leads to a syntax error. Thus if there was a variable called iter in scope, the example would be legal; it would just be interpreted as multiplication. Then when the programmer instantiated foo with ContainsAType, there would be an error because you can't multiply something by a type.

            typename states that the name that follows should be treated as a type. Otherwise, names are interpreted to refer to non-types.

            This rule even holds if it doesn't make sense even if it doesn't make sense to refer to a non-type. For instance, suppose we were to do something more typical and declare an iterator instead of a pointer to an iterator:

            template <class T>
            void foo() {
            typename T::iterator iter;
            ...
            }

            Even in this case, typename is required, and omitting it will cause compile error. As another example, typedefs also require use:

            template <class T>
            void foo() {
            typedef typename T::iterator iterator_type;
            ...
            }

            from:
            http://pages.cs.wisc.edu/~driscoll/typename.html
            posted on 2010-04-19 11:58 chatler 閱讀(455) 評(píng)論(0)  編輯 收藏 引用 所屬分類: Template
            <2008年7月>
            293012345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            常用鏈接

            留言簿(10)

            隨筆分類(307)

            隨筆檔案(297)

            algorithm

            Books_Free_Online

            C++

            database

            Linux

            Linux shell

            linux socket

            misce

            • cloudward
            • 感覺這個(gè)博客還是不錯(cuò),雖然做的東西和我不大相關(guān),覺得看看還是有好處的

            network

            OSS

            • Google Android
            • Android is a software stack for mobile devices that includes an operating system, middleware and key applications. This early look at the Android SDK provides the tools and APIs necessary to begin developing applications on the Android platform using the Java programming language.
            • os161 file list

            overall

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            国内精品久久久久影院老司| 亚洲国产天堂久久综合网站 | 久久只有这精品99| 色噜噜狠狠先锋影音久久| 久久午夜无码鲁丝片| 久久久久国产精品嫩草影院| 狠狠色丁香久久婷婷综合蜜芽五月| 久久av免费天堂小草播放| 色综合久久久久网| 亚洲国产精品久久66| 色综合久久久久| Xx性欧美肥妇精品久久久久久| av无码久久久久久不卡网站 | 99久久人妻无码精品系列| 亚洲综合伊人久久综合| 亚洲va久久久噜噜噜久久狠狠| 久久无码AV一区二区三区| 国产精品美女久久福利网站| 色综合合久久天天给综看| 中文成人无码精品久久久不卡| 一本大道久久东京热无码AV| 色妞色综合久久夜夜| 久久婷婷色综合一区二区| 欧美精品久久久久久久自慰| 99精品国产在热久久无毒不卡| 久久精品中文无码资源站| a级成人毛片久久| 91超碰碰碰碰久久久久久综合| 久久精品无码专区免费| 亚洲精品国产第一综合99久久 | 热综合一本伊人久久精品| 久久久精品久久久久影院| 少妇久久久久久被弄高潮| 精品久久久久久无码专区不卡| 狠狠色丁香久久综合五月| 久久99久久成人免费播放| 欧美伊人久久大香线蕉综合| 久久久精品人妻一区二区三区蜜桃 | 国产精品久久久天天影视香蕉 | 久久91精品国产91久| 久久久久亚洲av无码专区喷水|