개인 유형에서 자동을 사용할 수있는 이유는 무엇입니까?


139

다음 코드가 컴파일되어 실행된다는 것에 어떻게 든 놀랐습니다 (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;
}

이 코드가 제대로 컴파일되는 것이 맞습니까? 왜 정확합니까? auto개인 유형으로 사용할 수 있는데 예상대로 이름을 사용할 수없는 이유는 무엇 입니까?


11
있는 f.Baz().i그대로 확인 하십시오 std::cout << typeid(f.Baz()).name(). 클래스 외부의 코드는 반환 Baz()할 수 있는 유형을 "볼" 수 있으며 이름을 붙일 수는 없습니다.
Steve Jessop

2
그리고 그것이 이상하다고 생각한다면 (아마도 당신이 그것에 대해 묻는 것처럼) 당신은 유일한 것이 아닙니다.)이 전략은 Safe-Bool Idiom 과 같은 것들에 유용합니다 .
Matthieu M.

2
기억해야 할 것은 private컴파일러가 적용 할 수있는 방식으로 API를 설명 할 수있는 편의성이 있다는 것입니다. 의 Bar사용자가 유형 에 액세스하는 것을 방지하기위한 Foo것이 아니므 Foo로의 인스턴스를 반환하여 해당 액세스를 제공하는 데 방해가되지 않습니다 Bar.
Steve Jessop

1
"이 코드가 제대로 컴파일되는 것이 맞습니까?" 아닙니다 #include <iostream>. ;-)
LF

답변:


113

auto대부분 의 경우 규칙 은 템플릿 유형 공제와 동일합니다. 게시 된 예제는 개인 유형의 객체를 템플릿 함수에 전달할 수있는 것과 같은 이유로 작동합니다.

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

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

그리고 왜 개인 유형의 객체를 템플릿 함수에 전달할 수 있습니까? 유형의 이름 만 액세스 할 수 없기 때문입니다. 유형 자체는 여전히 사용할 수 있으므로 클라이언트 코드로 반환 할 수 있습니다.


32
그리고 이름 의 프라이버시가 type 과 관련이 없음을 확인 하려면 질문 public: typedef Bar return_type_from_Baz;의 클래스 Foo에 추가하십시오 . 이제 클래스의 개인 섹션에 정의되어 있지만 유형을 공개 이름으로 식별 할 수 있습니다.
Steve Jessop

1
스티브의 관점 @ 반복하려면 다음의 액세스 지정자 이름은 그것의와는 아무 상관이없는 유형 추가하여 볼 때, private: typedef Bar return_type_from_Baz;Foo같이 증명을 . typedef'd 식별자는 지정자 (공개 및 개인)에 액세스 할 수 없습니다.
damienh

이것은 나에게 이해가되지 않습니다. 유형 의 이름 은 실제 유형의 별명 일뿐입니다. 전화를 걸 Bar거나 무엇을하면 문제가 SomeDeducedType됩니까? 개인 회원 class Foo이나 다른 사람 에게 접근하는 데 사용할 수는 없습니다 .
einpoklum

107

액세스 제어는 이름에 적용됩니다 . 표준의이 예와 비교하십시오.

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
}

12

이 질문은 이미 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;
}

https://ideone.com/I5q7gw

해리 허점을 상기시켜 준 Quentin에게 감사드립니다.


5
friend class Harry;거기에 빠지지 않았 습니까?
Quentin

@Quentin 당신은 절대적으로 정확합니다! 완성도를 friend class Dumbledore;
높이기

Harry는 Wizard::LordVoldemort;현대 C ++ 을 호출 하여 자신이 무섭지 않다는 것을 보여주지 않습니다 . 대신에 그는 전화를한다 using Wizard::LordVoldemort;. (정직하게 Voldemort를 사용하는 것은 그리 자연스럽지 않습니다. ;-)
LF

8

여기에 문제가 정말 함께 할 수없는 것을 보여 98 ++ C에서 예입니다, 다른 (좋은) 답변을 추가하려면 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 ++에서 이름이없는 임시 유형을 작성해도됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.