简体   繁体   English

为什么我可以在私有类型上使用 auto ?

[英]Why can I use auto on a private type?

I was somehow surprised that the following code compiles and runs (vc2012 & gcc4.7.2)我对以下代码编译并运行感到惊讶(vc2012 & gcc4.7.2)

class Foo {
    struct Bar { int i; };
public:
    Bar Baz() { return Bar(); }
};

int main() {
    Foo f;
    // Foo::Bar b = f.Baz();  // error
    auto b = f.Baz();         // ok
    std::cout << b.i;
}

Is it correct that this code compiles fine?这段代码编译是否正确? And why is it correct?为什么它是正确的? Why can I use auto on a private type, while I can't use its name (as expected)?为什么我可以在私有类型上使用auto ,而我不能使用它的名称(如预期的那样)?

The rules for auto are, for the most part, the same as for template type deduction. auto的规则在很大程度上与模板类型推导相同。 The example posted works for the same reason you can pass objects of private types to template functions:发布的示例与您可以将私有类型的对象传递给模板函数的原因相同:

template <typename T>
void fun(T t) {}

int main() {
    Foo f;
    fun(f.Baz());         // ok
}

And why can we pass objects of private types to template functions, you ask?你问为什么我们可以将私有类型的对象传递给模板函数? Because only the name of the type is inaccessible.因为只有类型的名称是不可访问的。 The type itself is still usable, which is why you can return it to client code at all.类型本身仍然可用,这就是您完全可以将其返回给客户端代码的原因。

Access control is applied to names .访问控制应用于名称 Compare to this example from the standard:与标准中的此示例进行比较:

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
}

This question has already been answered very well by both chill and R. Martinho Fernandes. chill 和 R. Martinho Fernandes 已经很好地回答了这个问题。

I just couldn't pass up the opportunity to answer a question with a Harry Potter analogy:我不能错过用哈利波特比喻回答问题的机会:

class Wizard
{
private:
    class LordVoldemort
    {
        void avada_kedavra()
        {
            // scary stuff
        }
    };
public:
    using HeWhoMustNotBeNamed = LordVoldemort;

    friend class Harry;
};

class Harry : Wizard
{
public:
    Wizard::LordVoldemort;
};

int main()
{
    Wizard::HeWhoMustNotBeNamed tom; // OK
    // Wizard::LordVoldemort not_allowed; // Not OK
    Harry::LordVoldemort im_not_scared; // OK
    return 0;
}

https://ideone.com/I5q7gw https://ideone.com/I5q7gw

Thanks to Quentin for reminding me of the Harry loophole.感谢 Quentin 让我想起了 Harry 的漏洞。

To add to the other (good) answers, here's an example from C++98 that illustrates that the issue really doesn't have to do with auto at all要添加其他(好的)答案,这里有一个来自 C++98 的示例,说明该问题实际上与auto完全无关

class Foo {
  struct Bar { int i; };
public:
  Bar Baz() { return Bar(); }
  void Qaz(Bar) {}
};

int main() {
  Foo f;
  f.Qaz(f.Baz()); // Ok
  // Foo::Bar x = f.Baz();
  // f.Qaz(x);
  // Error: error: ‘struct Foo::Bar’ is private
}

Using the private type isn't prohibited, it was only naming the type.不禁止使用私有类型,它只是命名类型。 Creating an unnamed temporary of that type is okay, for instance, in all versions of C++.创建该类型的未命名临时文件是可以的,例如,在所有版本的 C++ 中。

对于其他来到这里并需要解决方法的人(例如,声明一个接受私有类型的函数),这就是我所做的:

void Func(decltype(Foo().Baz()) param) {...}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM