What is the difference between 'typedef' and 'using' in C++11?

后端 未结 7 820
误落风尘
误落风尘 2020-11-22 03:32

I know that in C++11 we can now use using to write type alias, like typedefs:

typedef int MyInt;

Is, from what I

7条回答
  •  死守一世寂寞
    2020-11-22 04:20

    All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.


    Typedef declarations can, whereas alias declarations cannot, be used as initialization statements

    But, with the first two non-template examples, are there any other subtle differences in the standard?

    • Differences in semantics: none.
    • Differences in allowed contexts: some(1).

    (1) In addition to the examples of alias templates, which has already been mentioned in the original post.

    Same semantics

    As governed by [dcl.typedef]/2 [extract, emphasis mine]

    [dcl.typedef]/2 A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. Such a typedef-name has the same semantics as if it were introduced by the typedef specifier. [...]

    a typedef-name introduced by an alias-declaration has the same semantics as if it were introduced by the typedef declaration.

    Subtle difference in allowed contexts

    However, this does not imply that the two variations have the same restrictions w.r.t. in which contexts they may be used. And indeed, albeit a corner case, a typedef declaration is an init-statement and may thus be used in contexts which allows initialization statements

    // C++11 (C++03) (init. statement in for loop iteration statements).
    for(typedef int Foo; Foo{} != 0;) {}
    
    // C++17 (if and switch initialization statements).
    if (typedef int Foo; true) { (void)Foo{}; }
    //  ^^^^^^^^^^^^^^^ init-statement
    
    switch(typedef int Foo; 0) { case 0: (void)Foo{}; }
    //     ^^^^^^^^^^^^^^^ init-statement
    
    // C++20 (range-based for loop initialization statements).
    std::vector v{1, 2, 3};
    for(typedef int Foo; Foo f : v) { (void)f; }
    //  ^^^^^^^^^^^^^^^ init-statement
    
    for(typedef struct { int x; int y;} P;
    //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ init-statement
        auto [x, y] : {P{1, 1}, {1, 2}, {3, 5}}) { (void)x; (void)y; }
    

    whereas an alias-declaration is not an init-statement, and may thus not be used in contexts which allows initialization statements

    // C++ 11.
    for(using Foo = int; Foo{} != 0;) {}
    //  ^^^^^^^^^^^^^^^ error: expected expression
    
    // C++17 (initialization expressions in switch and if statements).
    if (using Foo = int; true) { (void)Foo{}; }
    //  ^^^^^^^^^^^^^^^ error: expected expression
    
    switch(using Foo = int; 0) { case 0: (void)Foo{}; }
    //     ^^^^^^^^^^^^^^^ error: expected expression
    
    // C++20 (range-based for loop initialization statements).
    std::vector v{1, 2, 3};
    for(using Foo = int; Foo f : v) { (void)f; }
    //  ^^^^^^^^^^^^^^^ error: expected expression
    

提交回复
热议问题