次のコードがコンパイルされて実行されることになんとなく驚いた(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
を使用できるのに、その名前を(期待どおり)使用できないのはなぜですか?
auto
のルールは、ほとんどの場合、テンプレートタイプの控除と同じです。投稿された例は、プライベートタイプのオブジェクトをテンプレート関数に渡すことができるのと同じ理由で機能します。
template <typename T>
void fun(T t) {}
int main() {
Foo f;
fun(f.Baz()); // ok
}
そして、なぜ私たちはプライベート型のオブジェクトをテンプレート関数に渡すことができるのですか?タイプの名前だけにアクセスできないからです。タイプ自体はまだ使用可能です。そのため、クライアントコードにタイプを返すことができます。
アクセス制御はnamesに適用されます。標準のこの例と比較してください:
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
}
この質問は、チルとR.マルティーニョフェルナンデスの両方によって非常によく回答されています。
私はハリー・ポッターの例えで質問に答える機会を逃すことができませんでした:
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;
}
ハリーの抜け穴を思い出させてくれたクエンティンに感謝します。
他の(良い)回答に追加するために、問題がauto
とまったく関係がないことを示すC++ 98の例を次に示します
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++のすべてのバージョンで問題ありません。