Visibility of private field of a template class from a template function - c++

I have a template class
template<class T>
class MyClass
{
public:
MyClass() { privateField = 0; };
T getPrivateField() {
return privateField;
}
private:
T privateField;
};
and a template function which takes an instance of MyClass as a parameter
template<class T>
T foo(MyClass<T> mc) {
return mc.privateField;
}
I was confused by the fact that I can see a private field of MyClass in template function, but can't actually use it.
Here is an example of field visibility(screenshot)
Question:
Why can I see a private field of MyClass exactly in a template function and how can I disable it in my code(if it's possible)? Or it's just like a feature from Visual Studio?

private will limit your code's access to a member.
It does not make parts of your code invisible to tools that might make observations about what you have written. It's not private in the sense that a personal password might be private.

private does not mean that it is completely hidden from the outside, or that nobody outside of the class should be aware that it exists.
Consider this example:
#include <iostream>
struct foo {
int x = 0;
};
struct bar : foo {
private:
int x = 0;
};
int main() {
bar b;
b.x = 0;
}
Now suppose, main was written by a user who only knows about the public parts of the involved classes. They would have no way to understand why they get the error message:
<source>: In function 'int main()':
<source>:15:7: error: 'int bar::x' is private within this context
15 | b.x = 0;
| ^
<source>:10:13: note: declared private here
10 | int x = 0;
| ^
Admittetly this is a made up example, and bar can be considered broken. The point is just that your IDE would not necessarily do you a favor if it would not show any private members. Their presence or absence can change the meaning of code that is written only against the public interface.

Do not confuse visibility with access.
Consider how overload resolution behaves:
class X {
private:
void f(int value);
public:
void f(double value);
};
If we try to call X::f() with an int from outside:
int main() {
X obj;
obj.f(1234);
}
We still get the error:
<source>:10:15: error: 'void X::f(int)' is private within this context
obj.f(1234);
We definitely would not want main to call X::f(double) simply because it could not access the X::f(int) function. Otherwise, access could literally change the runtime meaning of your program.
C++ will
build an overload set from name lookup
perform resolution to pick the best match
verify access
In that order. That is, access is checked after the overload resolution has completed.

Related

C++ template friend declaration for known class name nested in any other

Good evening.
I have the following problem in writing some generic code (in C++11 at least):
Consider a class named I that may be nested in various classes A, B,...,N:
class A
{
protected:
friend class I;
class I
{
} i;
};
class B
{
protected:
friend class I;
class I
{
} i;
};
etc.
Actually I is a kind of interface tool, automatically inserted in various user classes A...N. Don't care of the reason to do that...
Then there is a specific class Z and the goal is to declare any I as friend of Z, so that any I and nothing else can use Z, whatever class A...N (defined later) the I will be nested in.
If I declare this way:
class Z
{
friend class A; // <--- but I don't want to have to know this one
friend class I;
private: // creation and use of Z are restricted to tools like I
Z();
// other methods
};
Then it works for A::I only:
From A::I::some_function() it is possible to build and use a Z,
but not from B::I nor any other in B...N.
Without the friend class A;, none of the I can access Z.
How to get it generic ?
I'm looking for a way to write a template friend declaration granting the access for any X::I where X is the template parameter.
And not a template parameter for I of course, since I is not a template.
Of course I do not want to grant access to any class X so that any X::I can access Z too !
The following does not work:
class Z
{
template< class X> friend class X::I;
...
};
=> error: 'I' is not a member of 'X'
from gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11)
Any idea of the correct syntax ? I did not find that use case in the reference...
Thanks a lot,
Kind regards.
================= added on Aug. 16 : Precisions:
The I exists durably as part of the A (or other) while the Z is a tool living only during a particular operation of the I, that may be repeated, then a new Z is created, used then deleted everytime as a local of a method of I.
Also the Z has a consequent payload and I don't want to make it a permanent part of every object embedding a I. For instance by making Z inherited by I.
You can probably achieve what you're trying to do by making I inherit Z, and make Z an abstract base class (so it can't be accessed directly).
Something similar to:
class Z
{
virtual void __() = 0;
public:
virtual ~Z() = default;
void method() { std::cout << "Method from Z" << std::endl; }
};
class A
{
friend class I;
public:
class I : public Z
{
void __() final {}
public:
static Z *make_z();
} i;
};
Z *A::I::make_z()
{
return new I();
}
int main()
{
Z *z = A::I::make_z();
z->method();
return 0;
}

C++ Template Method Overloading and Class Access with Polymorphism

I noticed something which I think is pretty interesting behaviour.
Consider the following example code which I tried to keep as generic as possible:
class Base
{
public:
virtual void func() {}
};
class Subclass : public Base
{
public:
void func() {}
};
class ApplyingClass
{
public:
static void callFunc(Base& base) { base.func(); }
private:
template <class T>
static void callFunc(T& t) { t.func(); }
};
int main()
{
Subclass s;
Base& b = s;
// Error: ApplyingClass::callFunc(T& t) with T=Subclass is private.
ApplyingClass::callFunc(s);
// works
ApplyingClass::callFunc(b);
return 0;
}
It seems that inside main(), due to the template method being present, the compiler sees the template "ApplyingClass::callFunc(T& t)" as the right fit for the function call "ApplyingClass::callFunc(s)" and throws an Error since the method is not accessible from outside it's class.
This seems logical, yet I expected the compiler to still go and try to use "ApplyingClass::callFunc(Base& base)" since the method signature fits and this is the only accessible fitting method.
To take my point a bit further; if I were to remove the private template method from ApplyingClass, both function calls inside main() would be valid.
My question now is whether this is part of the C++ specification or if this is compiler specific behaviour (this was tested using the Visual Studio 2017 ver 15.5.7 compiler).
It's valid C++ to emit an error here.
See [class.member.lookup]:
If the name of an overloaded function is unambiguously found, overload resolution also takes place before
access control.
So the appropriate overload is selected first (the template), and then access control happens, which causes a compiler error.

non-static data member initialization from mother protected field

I have an issue trying to use non-static data member init. in a complex template inheritance chain. I attach a small non-working example:
struct Builder {
template <typename T> T& get() {
return a;
};
float a = 5;
};
struct Base {
Builder a;
};
template <typename T> struct A: public Base {};
template <typename T> struct B: public A<T> {
float& b = (A<T>::a).get<float>(); // Do not work
Builder& builder = A<T>::a;
float& c = builder.get<float>(); // Work
};
struct C: public A<float> {
float& b = a.get<float>(); // Work
};
int main() {
return 0;
}
I'm most interested in class B. I have a compilation error using gcc 4.9.2:
error: expected primary-expression before ‘float’
float& b = (A<T>::a).get<float>(); // Do not work
I don't understand why it does not work as ti does compile if I use the trick two lines below (suffixed by the comment Work) which is basically the same thing.
It also works out of the box if my class is not a template. In this case, I can directly access the protected field by its name without using the syntaxe ParentClass<T>::field.
Do you have any ideas of what I'm doing wrong here?
Thanks a lot for your help!
Here get is a dependent name (it depends on T). You need to explicitly state it's the name of a template :
float& b = A<T>::a.template get<float>();
The second one works because you explicitly "collapse" A<T>::a into a Builder&, which does not depend on T anymore.
The third one works because you inherit from the fully specialized A<float>, which again does not depend on T.

Friend function is unable to construct a unique pointer of the class

I have a certain design strategy where the constructor of my class is private and can only be constructed by friends of the class. Inside the friend function, I am trying to create a unique_pointer of my class using std::make_uniquebut it doesn't compile. My VC12 compiler complains
c:\program files (x86)\microsoft visual studio
12.0\vc\include\memory(1639): error C2248: 'Spam::Spam' : cannot access private member declared in class 'Spam'
The relevant code which fails during compilation is as follows
#include <memory>
class Spam {
public:
friend void Foo();
private:
Spam(int mem) :mem(mem) {}
int mem;
};
void Foo() {
std::unique_ptr<Spam> spam = std::make_unique<Spam>(10);
}
Why am I not able to compile?
In your case the function make_unique is trying to create an instance of Spam and that function is not a friend. Calling a non-friend function from inside a friend function does not imbue the non-friend function with friend status.
To solve this you can write in Foo:
std::unique_ptr<Spam> spam(new Spam(10));
Here is another approach I've seen used, apparently known as the passkey idiom : have the public constructor require a private access token.
class Spam {
struct Token {};
friend void Foo();
public:
Spam(Token, int mem) : mem(mem) {}
private:
int mem;
};
void Foo() {
std::unique_ptr<Spam> spam = std::make_unique<Spam>(Spam::Token{}, 10);
}
void Bar() {
// error: 'Spam::Token Spam::token' is private
// std::unique_ptr<Spam> spam = std::make_unique<Spam>(Spam::Token{}, 10);
}
Why am I not able to compile?
You are unable to compile because make_unique is not a friend of Spam.
An alternative solution to making make_unique a friend is to move the creation of the unique_ptr into Spam.
class Spam {
...
private:
Spam(int) {}
static unique_ptr<Spam> create( int i )
{ return std::unique_ptr<Spam>( new Spam(i) ); }
};
and then have Foo call that instead.
void Foo() {
std::unique_ptr<Spam> spam = Spam::create(10);
...
}
In your example, Foo() is a friend, but it isn't the function that's creating the Spam - make_unique is internally calling new Spam itself. The simple fix is to just have Foo() actually construct the Spam directly:
void Foo() {
std::unique_ptr<Spam> spam(new Spam(10));
}

a in-class class access the outer class's data member

I was trying to do this,
class Outer {
public:
struct inner_t {
void foo()
{
printf("%d", _x);
}
};
int _x;
};
int main()
{
Outer o;
o._x = 10;
}
The above can't compile with errors:
error: invalid use of non-static data member ‘Outer::_x’
But according to this post, inner_t can indeed access Outer::_x, what's wrong?
The problem is: inner_t does not know an instance of Outer to read _x from.
If you had written (for example):
void foo(const Outer *o)
{
printf("%d", o->_x);
}
Or if _x was a static member of Outer.
Then it should work (at least it will give no error).
You can indeed access _x of object of type Outer. You try basically to access instance field in static fashion. Pass an instance of Outer and then use it.