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

C++ 为什么我可以在私有类型上使用auto?,c++,c++11,auto,private-members,C++,C++11,Auto,Private Members,不知何故,我对以下代码的编译和运行感到惊讶(vc2012和gcc4.7.2) class-Foo{ 结构条{int i;}; 公众: Baz(){return Bar();} }; int main(){ 福福; //Foo::Bar b=f.Baz();//错误 自动b=f.Baz();//确定 std::cout大多数情况下,auto的规则与模板类型推断的规则相同。发布的示例的工作原理与您可以将私有类型的对象传递给模板函数的原因相同: template <typename T>

不知何故,我对以下代码的编译和运行感到惊讶(vc2012和gcc4.7.2)

class-Foo{
结构条{int i;};
公众:
Baz(){return Bar();}
};
int main(){
福福;
//Foo::Bar b=f.Baz();//错误
自动b=f.Baz();//确定

std::cout大多数情况下,
auto
的规则与模板类型推断的规则相同。发布的示例的工作原理与您可以将私有类型的对象传递给模板函数的原因相同:

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

int main() {
    Foo f;
    fun(f.Baz());         // ok
}
模板
void fun(T){}
int main(){
福福;
乐趣(f.Baz());//好的
}

您会问,为什么我们可以将私有类型的对象传递给模板函数?因为只有类型的名称是不可访问的。类型本身仍然可用,这就是为什么您可以将其返回到客户端代码。

访问控制应用于名称。与标准中的示例相比:

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
}
为了补充其他(好的)答案,这里有一个来自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
}

使用私有类型不被禁止,它只是命名类型。创建一个未命名的临时类型是可以的,例如,在所有版本的C++中。

< P>这两个问题已经被ChILL和R. Martinho Fernandes都很好地回答了。 我不能错过这个机会,用哈利波特的比喻来回答一个问题:

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;
}


感谢昆汀提醒我哈利的漏洞。

要知道名字的私密性与类型无关,请将
public:typedef Bar return\u type_from_Baz;
添加到问题中的类
Foo
。现在,尽管在类的私有部分定义了该类型,但该类型可以通过公共名称来识别。To重复@Steve的观点:名称的访问说明符与它的类型无关,通过将
private:typedef Bar return\u type_from_Baz;
添加到
Foo
,可以看出,
typedef
'd标识符对访问说明符(public和private)没有任何意义。类型的名称只是一个别名对于实际类型。如果我称它为
Bar
someDescelledType
,又有什么关系呢?我不可能用它来联系
class Foo
或任何东西的私人成员。请注意
f.Baz().I
也可以,就像
std::cout一样,如果你认为它很奇怪的话(当你问起这件事时,你可能会问)你不是唯一一个;)这个策略对于类似的东西非常有用。我想需要记住的是,
private
是为了方便描述API,编译器可以帮助实现。它不是为了阻止
Foo
的用户访问类型
Bar
,所以它不会妨碍
Foo
通过返回
Bar
的一个实例来提供该访问的任何方法“此代码编译良好是否正确?”“不,你需要<代码> >包含<代码> >;-)不是< Harry >朋友类;在这里丢失了吗?“昆廷,你绝对正确!为了完整性,我们应该也应该添加<代码>朋友类邓布利多; >;”Harry没有显示他不害怕调用<代码>向导::LordVoldemort;< /C> >在现代C++中。code>使用Wizard::LordVoldemort;
(老实说,使用伏地魔感觉不太自然;-)应该使用Wizard::LordVoldemort吗?
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;
}