c++ access protected member via auto [duplicate] - c++

I was somehow surprised that the following code compiles and runs (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)?

The rules for auto are, for the most part, the same as for template type deduction. 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.
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
Thanks to Quentin for reminding me of the Harry loophole.

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
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++.

For anyone else coming here and needs a workaround (e.g. for declaring a function that accepts the private type), this is what I did:
void Func(decltype(Foo().Baz()) param) {...}

Related

Why is it allowed to deduce a private type? [duplicate]

I was somehow surprised that the following code compiles and runs (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)?
The rules for auto are, for the most part, the same as for template type deduction. 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.
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
Thanks to Quentin for reminding me of the Harry loophole.
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
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++.
For anyone else coming here and needs a workaround (e.g. for declaring a function that accepts the private type), this is what I did:
void Func(decltype(Foo().Baz()) param) {...}

private innerclass can be accessed when via auto variable [duplicate]

I was somehow surprised that the following code compiles and runs (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)?
The rules for auto are, for the most part, the same as for template type deduction. 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.
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
Thanks to Quentin for reminding me of the Harry loophole.
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
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++.
For anyone else coming here and needs a workaround (e.g. for declaring a function that accepts the private type), this is what I did:
void Func(decltype(Foo().Baz()) param) {...}

Why does the auto keyword allow creating instances of privately declared inner-classes or inner-structs? [duplicate]

I was somehow surprised that the following code compiles and runs (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)?
The rules for auto are, for the most part, the same as for template type deduction. 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.
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
Thanks to Quentin for reminding me of the Harry loophole.
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
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++.
For anyone else coming here and needs a workaround (e.g. for declaring a function that accepts the private type), this is what I did:
void Func(decltype(Foo().Baz()) param) {...}

Does auto changes internal types visibility in C++? [duplicate]

I was somehow surprised that the following code compiles and runs (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)?
The rules for auto are, for the most part, the same as for template type deduction. 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.
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
Thanks to Quentin for reminding me of the Harry loophole.
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
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++.
For anyone else coming here and needs a workaround (e.g. for declaring a function that accepts the private type), this is what I did:
void Func(decltype(Foo().Baz()) param) {...}

Why can I use auto on a private type?

I was somehow surprised that the following code compiles and runs (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)?
The rules for auto are, for the most part, the same as for template type deduction. 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.
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
Thanks to Quentin for reminding me of the Harry loophole.
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
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++.
For anyone else coming here and needs a workaround (e.g. for declaring a function that accepts the private type), this is what I did:
void Func(decltype(Foo().Baz()) param) {...}