What's the difference between type and name in C++?

前端 未结 3 1719
予麋鹿
予麋鹿 2021-01-01 12:28

I am reading this Stack Overflow question, and I added a constructor to the code from that question as the follwing,

class Foo {
    struct Bar { 
              


        
3条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-01-01 13:19

    [Some standardese ahead]

    Let's agree that auto deduction works in the same way as template argument deduction:

    [dcl.spec.auto]/p7

    If the placeholder is the auto type-specifier, the deduced type is determined using the rules for template argument deduction

    Templates are subject to the two-phase lookup during compilation. Access control is applied to name lookup in the first phase

    [basic.lookup]/p1

    Overload resolution (13.3) takes place after name lookup has succeeded. The access rules (Clause 11) are considered only once name lookup and function overload resolution (if applicable) have succeeded. Only after name lookup, function overload resolution (if applicable) and access checking have succeeded are the attributes introduced by the name’s declaration used further in expression processing

    auto and decltype(auto) are usually a placeholder for a deduced type, and it is true that [temp.arg]/p3 says

    The name of a template-argument shall be accessible at the point where it is used as a template-argument

    but names aren't involved here, only the types. Access control applies to names, a type can be mapped to 0, 1 or multiple names and that's what you're dealing with when using auto in the code above: it is semantically equivalent to the semantics of template deduction and this is by design.

    [class.access]/p4

    Access control is applied uniformly to all names, whether the names are referred to from declarations or expressions. [...] The accessibility of the entity referred to by the typedef is not considered. For example

    class A {
      class B { };
    public:
      typedef B BB;
    };
    void f() {
      A::BB x; // OK, typedef name A::BB is public
      A::B y; // access error, A::B is private
    }
    

    To convince yourself of the following take a look at the same code with template argument deduction involved (conceptually equivalent to the auto version)

    template 
    T deduce(T t) {
        return t;
    } 
    
    class Foo {
        struct Bar{ 
            int i; 
            Bar(int a = 5):i(a){}; 
        };
    public:
    
      Bar *getB() { return new Bar(5); } // Leaks, doesn't matter for clarity's sake
    };
    
    int main() {
        Foo f;
        std::cout <<"b.i="<< deduce(f.getB())->i <

    Live example

    In the code above names aren't involved and thus access control doesn't apply. Types are indeed involved.

    The semantics of auto is like implicit template deduction (the normative wording also directly refers to it).

    Someone else had this doubt before.


    Now for the answers:

    Case 1 is easy to agree with if you consider that the caller has no access to the name Foo::Bar.

    Case 2 exposes the name to the caller as well, so if you use the typedef'd name your code will happily compile.

提交回复
热议问题