I put the tag language lawyer, although I have the feeling that this is on the wrong side of the standard boundary. I haven't seen a conversation exactly on this point, and but I had at work, so I would like to have some certainty about this.
The issue is accessing (potentially) private fields of virtual base classes. Say I compute the offset of a private field of a class, and then use this offset outside the class to access (read/write) the member variable at this location.
I saw that there is an extension for GCC and clang offsetof (this one is conditionally defined in C++17, what does it mean?), and using it is equivalent to some pointer arithmetic like this:
#include <iostream>
class A
{
int a{};
public:
int aa{};
static ptrdiff_t getAOffset()
{
A instance;
return reinterpret_cast<ptrdiff_t>(static_cast<const void*>(&instance)) - reinterpret_cast<ptrdiff_t>(static_cast<const void*>(&(instance.a)));
//return offsetof(A, a); // "same" as this call to offset
}
int get() const
{
return a;
}
};
class B: public virtual A
{
};
void update_field(char* pointer, ptrdiff_t offset, int value)
{
int* field = reinterpret_cast<int*>(pointer + offset);
*field = value;
}
void modify_a(B& instance)
{
update_field(reinterpret_cast<char*>(dynamic_cast<A*>(&instance)), A::getAOffset(), 1);
}
int main()
{
B instance;
std::cout << instance.get() << std::endl;
modify_a(instance);
std::cout << instance.get() << std::endl;
}
I also made a coliru (pedantic) that doesn't complain, but still...
https://coliru.stacked-crooked.com/a/faecd0b248eff651
Is there something in the standard that authorizes this or is this in undefined behavior land? Happy to see also if there is a difference between the standards.
Related
I know this question gets asked a lot, but I have a specific use case, so I don't think it's a duplicate!
I have an abstract base class:
template<int N>
class Child;
class Base
{
public:
// Factory-like generation of children as Base
static Ptr<Base> New(int baseN)
{
if (baseN == 2) return new Child<2>();
else if (baseN == 3) return new Child<3>()
}
// Update
virtual void update() = 0;
};
And I'm writing some children of Base as class templates (on an int):
template<int N>
class Child
:
public Base
{
// Member, N is not the size of matrix, more like the size of a component in matrix
Matrix<N> m_member;
public:
// Implement update
virtual void update();
// Should call the passed callable on m_member
virtual void execute(std::function<void(Matrix<N>&)>&);
};
// Force compilation of Child<N> for some values of N (of interest, including 3) here
// Then,
int baseN = 3;
Ptr<Base> obj = Base::New(baseN); // will get me a Child<3> as a Base object
auto callable = [](Matrix<3>) ->void {};
// Can I access Child<3>::m_member ??
// Can't cast to Child<baseN> (baseN is not constexpr) and don't want to
// But want to do something like:
obj->execute(callable);
// Which forwards 'callable' to the method from concrete type, probably using a cast?
In short, I need to have some sort of access to m_member from the declared Base object.
Preferably, a way to call Child<N>::execute from Base without making Base a template on N too.
Things I've tried/thought-of include:
'Type erasure' of Matrix<N> by hiding them behind an interface, but because Matrix<N>'s interface strongly depends on N, doing that renders the classes useless (think: Vector<N>& Matrix<N>::diag() for example)
Can Base::New do anything to record what concrete type it creates? I doubt that because types are not objects.
EDIT: (Btw this is C++11)
So, I accidentally figured out a way to do this; but I don't quite understand why the following works (Not well versed into assembly yet):
I'm using a Database for objects (unordered_map<string, object*> where object is a class that every registered object has to inherit from).
When a Child is created, we register it to a database with a name of Child<N>.
Then, at application-level code, there is a findChild<int N> template which employs compile-time recursion to find which concrete class was the Base pointer created from (At runTime, by dynamicCasting and testing). When It finds it, it can cast it to void* through a static method (findChild<N>::castToConcrete)
What's interesting is that we can somehow use findChild<0> to access the findChild<N> in question if Child<N> is polymorphic. This forces us to have at most one object of Child (for all possible Ns) and I certainly can live with that.
You can see and inspect a minimal code example here: https://onlinegdb.com/CiGR1Fq5z
What I'm so confused about is that Child<0> and other Child<N> are completely different types; So how can we access one's members from a pointer to another type? I'm most likely relying on UB and even fear there is a stack smacking of some sort!
For reference, I'm including the code here in case the link dies.
#include <unordered_map>
#include <vector>
#include <functional>
#include <iostream>
using namespace std;
#ifndef MAX_N_VALUE
#define MAX_N_VALUE 10
#endif // !MAX_N_VALUE
// ------------------ Lib code
// A dummy number class for testing only
template <int N> struct Number { constexpr static int value = N; };
// Objects to register to the database
struct object
{
// Members
string name;
// construction/Destruction
object(const string& name) : name(name) {}
virtual ~object(){};
};
// Database of objects
struct DB
: public unordered_map<string, object*>
{
// See if we can the object of name "name" and type "T" in the DB
template <class T>
bool found(const string& name) const
{
unordered_map<string,object*>::const_iterator iter = find(name);
if (iter != end())
{
const T* ptr = dynamic_cast<const T*>(iter->second);
if (ptr) return true;
cout << name << " found but it's of another type." << endl;
return false;
}
cout << name << " not found." << endl;
return false;
}
// Return a const ref to the object of name "name" and type "T" in the DB
// if found. Else, fails
template <class T>
const T& getObjectRef(const string& name) const
{
unordered_map<string,object*>::const_iterator iter = find(name);
if (iter != end())
{
const T* ptr = dynamic_cast<const T*>(iter->second);
if (ptr) return *ptr;
cout << name << " found but it's of another type." << endl;
abort();
}
cout << name << " not found." << endl;
abort();
}
};
// Forward declare children templates
template<int N>
class Child;
// The interface class
struct Base
{
// Construction/Destruction
protected:
static unsigned counter;
Base(){}
public:
virtual ~Base() {}
// Factory-like generation of children as Base
// THIS New method needs to know how to construct Child<N>
// so defining it after Child<N>
static Base* New(int baseN, DB& db);
// Update
virtual void update() = 0;
// Call a callable on a child, the callable interface
// however is independent on N
virtual void execute(std::function<void(Base&)>& callable)
{
callable(*this);
}
};
unsigned Base::counter = 0;
// The concrete types, which we register to the DB
template<int N>
struct Child
:
public Base, public object
{
// members
vector<Number<N>> member;
// Construction/Destruction
Child() : Base(), object(string("Child") + to_string(N) + ">"), member(N, Number<N>()) {}
virtual ~Child() {}
// Test member method (Has to be virtual)
virtual vector<Number<N>> test() const
{
cout << "Calling Child<" << N << ">::test()" << endl;
return vector<Number<N>>(N, Number<N>());
}
// Implement update
virtual void update()
{
cout << "Calling Child<" << N << ">::update()" << endl;
};
};
// New Base, This can be much more sophisticated
// if static members are leveraged to register constructors
// and invoke them on demand.
Base* Base::New(int baseN, DB& db)
{
if (baseN == 2)
{
Child<2>* c = new Child<2>();
db.insert({string("Child<")+std::to_string(2)+">", c});
return c;
}
if (baseN == 3)
{
Child<3>* c = new Child<3>();
db.insert({string("Child<")+std::to_string(3)+">", c});
return c;
}
return nullptr;
}
// Finder template for registered children
template<int N>
struct findChild
{
// Concrete Type we're matching against
using type = Child<N>;
// Stop the recursion?
static bool stop;
// Compile-time recursion until the correct Child is caught
// Recursion goes UP in N values
static void* castToConcrete(const DB& db, Base* system)
{
if (N > MAX_N_VALUE) stop = true;
if (stop) return nullptr;
if (db.found<type>(string("Child<")+to_string(N)+">"))
{
type* ptr = dynamic_cast<type*>(system);
return static_cast<void*>(ptr);
}
// NOTE: This should jump to the next "compiled" child, not just N+1, but meh;
return findChild<N+1>::castToConcrete(db, system);
}
};
// Activate recursive behaviour for arbitraty N
template<int N>
bool findChild<N>::stop = false;
// Explicit specialization to stop the Compile-time recursion at a decent child
template<>
struct findChild<MAX_N_VALUE+1>
{
using type = Child<MAX_N_VALUE+1>;
static bool stop;
static void* castToConcrete(const DB& t, const Base* system)
{
return nullptr;
}
};
// Disactivate recursive behaviour for N = 11
bool findChild<MAX_N_VALUE+1>::stop = true;
// ------------------ App code
int main()
{
// Create objects database
DB db;
// --- Part 1: Application writers can't write generic-enough code
// Select (from compiled children) a new Base object with N = 2
// and register it to the DB
Base* b = Base::New(2, db);
b->update();
cout << "Access children by explicit dynamic_cast to Child<N>:" << endl;
// Get to the object through the objects DB.
// Child destructor should remove the object from DB too, nut meh again
const auto& oo = db.getObjectRef<Child<2>>("Child<2>");
cout << oo.test().size() << endl;
// --- Part 2: Application writers can write generic code if the compile
// Child<N> for their N
cout << "If Child<N> is polymorphic, we can access the correct child from findChild<0>:" << endl;
// Create a lambda that knows about db, which Base applies on itself
function<void(Base&)> lambda = [&db](Base& base) -> void {
// Cast and ignore the result
void* ptr = findChild<0>::castToConcrete(db, &base);
// Cast back to Child<0>
findChild<0>::type* c = static_cast<findChild<0>::type*>(ptr);
// Now access original Child<N> methods and members from Child<0>
cout << "Method:\n" << c->test().size() << endl;
cout << "Member:\n" << c->member.size() << endl;
};
b->execute(lambda);
return 0;
}
I compiled with GCC 9 with the following options:
-m64 -Wall -Wextra -Wno-unused-parameter -Wold-style-cast -Wnon-virtual-dtor -O0 -fdefault-inline -ftemplate-depth-200
It seems you want inheritance to group not so related classes...
std::variant (C++17) might be more appropriate:
template<int N>
class Child
{
// Member, N is not the size of matrix, more like the size of a component in matrix
Matrix<N> m_member;
public:
void update();
void execute(std::function<void(Matrix<N>&)> f) { f(m_member); }
};
using Base = std::variant<Child<2>, Child<3>>;
and then:
void foo(Base& obj)
{
struct Visitor {
template <std::size_t N>
void operator()(Child<N>& c) const
{
auto callable = [](Matrix<N>) -> void {/*..*/};
c.execute(callable);
}
} visitor;
std::visit(visitor, obj);
}
To answer to your Edit, whereas your callable take a Base, you might chain the dynamic_cast as follow:
template <int N>
void foo_base(Base& b)
{
if (auto* child = dynamic_cast<Child<N>*>(&b)) {
// Job with Child<N>
std::cout << "Method:" << child->test().size() << std::endl;
std::cout << "Member:" << child->member.size() << std::endl;
}
}
template <int... Ns>
void foo_dispatch(std::integer_sequence<int, Ns...>, Base& base)
{
//(foo_base<Ns>(base), ...); // C++17
const int dummy[] = {0, (foo_base<Ns>(base), 0)...};
static_cast<void>(dummy); // Avoid warning about unused variable
}
With a call similar to:
function<void(Base&)> lambda = [](Base& base) {
//foo_dispatch(std::integer_sequence<int, 2, 3>(), base);
foo_dispatch(std::make_integer_sequence<int, MAX_N_VALUE>(), base);
};
Demo
(std::integer_sequence is C++14, but can be implemented in C++11)
Note: Jarod's answer is still a little bit better if you know possible
values of N in Child<N> at compile-time and don't want to provide a way to extend them. Plus, of course, if you can use C++17.
Here I'm relying on "Similar types" defined by the standard as:
4.4 Qualification conversions [conv.equal]
... trimmed ...
Two pointer types T1 and T2 are similar if there exists a type T and integer n > 0 such that:
T1 is cv(1,0) pointer to cv(1,1) pointer to ··· cv(1,n−1) pointer to cv(1,n) T
and
T2 is cv(2,0) pointer to cv(2,1) pointer to ··· cv(2,n−1) pointer to (cv2,n) T
where each cv(i,j) is const, volatile, const volatile, or nothing
The same paragraph also shows the conditions for converting expressions.
In short, By inheriting from Base, all Child<N>* pointer types are similar to Base*, hence similar to each other.
Now, we know we can static_cast Child<N> to Child<0> without problems.
But is accessing Child<3> members from a Child<0>* safe?
3.10 Lvalues and rvalues [basic.lval]
If a program attempts to access the stored value of an object through a glvalue of other than one of the
following types the behavior is undefined:
the dynamic type of the object,
... trimmed ...
a type similar (as defined in 4.4) to the dynamic type of the object
There you have it, Accessing the values of Child<3> though a Child<0>* is in fact defined behavior.
This piece of code:
Base* b = Base::New(2);
b->update();
Child<2>* c1 = static_cast<Child<2>*>(b);
c1->update();
cout << c1->t.sValue << " " << c1->t.rValue << endl;
Child<0>* c2 = static_cast<Child<0>*>(b);
c2->update();
cout << c2->t.sValue << " " << c2->t.rValue << endl;
Will actually output (Note the value of the static variable Test<N>::sValue):
Calling Child<2>::update()
Calling Child<2>::update()
2 2
Calling Child<2>::update()
0 2
Static members will always point to Child<0>, and because of that,
Jarod's answer is a better solution for this problem.
But if one wants to allow expanding possible N values, this solution is OK; you just have to remember to put your static variables in Base and not in Child<N>.
Here is a minimal example, showing how to pass a lambda to the Base* while in fact the lambda, casts the pointer to Child<0> and operates on it:
https://onlinegdb.com/TTcMqOmWi
My solution I gonna use to add “C++ Extension Methods” to JNI jobjects to make NDK code more readable like (Uniform Function Call Syntax) is:
Subclass the class that I want to add extension methods.
For invoking the “Extension Methods” make a pointer of type ExtensionsClass to point to OriginalClass - (Although the pointed object is’nt an ExtensionsClass).
The overload is minimal & we can access public methods of the Original class.
#include <iostream>
// Represents a class external to my source
class Person {
public:
Person(){
privateage = 20;
}
int age() { return privateage; }
private:
int privateage;
short anotherField;
};
class PersonExtensions : private Person {
public:
inline int size() { return 5 + age(); }
//NoFieldsOnExtensionClass
};
int main() {
Person person;
PersonExtensions* pE = (PersonExtensions*) &person;
std::cout << pE -> size() << std::endl;
std::cout << (*pE).size() << std::endl;
std::cout << sizeof(Person) << std::endl;
std::cout << sizeof(PersonExtensions) << std::endl;
return 0;
}
Do you think that this incorrect pointer assignment, since “Extension Method” only accessed public members of extended class & extension class don’t going to have any Field variables, can represent a problem in the future?
The size of the object are the same.
Thanks a lot.
This is undefined behaviour.
Yes that can break at any point.
Consider overloading ->* or something instead.
Or just using a free function.
If you really want infix notation:
template<class T, class F>
struct extension_method_t {
F f;
friend auto operator->*( T& t, extension_method_t const& self ) {
return [&t,&self](auto&&...args)->decltype(auto) {
return self.f( t, decltype(args)(args)... );
};
}
};
template< class T, class F >
extension_method_t<T,F> extension_method( F f ) {
return {std::move(f)};
}
then:
auto size = extension_method<Person>([](auto& person)->int{
return 5+person.age();
});
Person p;
std::cout << (p->*size)() << "\n"; // prints p.age()+5
here we don't have an extension method, but we do have an extension method pointer.
What you are doing in your question code is Undefined Behavior, so an especially an optimizing compiler might do really "fun" things with it. In other words, don't do it, it might break at any time even if it works when you test it. Only way to make sure it would actually work would be to examine the produced assembly code after each compilation to make sure it does what you want, and this is essentially impossible, so it is never safe.
You are using private inheritance. So for same effect you can just do this:
class PersonExtensions {
public:
PersonExtensions(Person *person) : _person(person) {}
inline int size() { return 5 + _person->age(); }
private:
Person *_person;
};
If you instead used public inheritance (so you could just call Person methods through PersonExtensions), then you'd need to add a getter for _person (for cases where real Person is needed), and/or add delegates for Person methods (for so called static polymorphism).
I have a class such as
class Stuff
{
private:
int x;
virtual int buisness()
{
return 42;
}
public:
Stuff(){
x = 5;
}
Given a pointer to an instance of this class
Stuff stuff;
void* thing = &stuff;
How would I get a pointer to the variable x and a pointer to the virtual function table of that class using just the pointer "thing"?
Edit: to clarify this was a challenge sent to me and I have been assured that it is not a trick question.
How would I get a pointer to the variable x and a pointer to the virtual function table of that class using just the pointer "thing"?
You can't without casting thing back to the original type:
Stuff* stuff2 = reinterpret_cast<Stuff*>(thing);
and at least that doesn't redeem you from privacy policies of that class, and how you could access class member pointers publicly.
The actual layout is implementation defined, and trying to use offsets from thing and size assumptions is beyond standard c++ mechanisms.
It sounds like you want to circumvent the private member access policies of a class with known layout of these members. Here's an extremely dirty hack:
Disclamer: Don't do that in production code!!
#include <iostream>
class Stuff {
private:
int x;
virtual int business() {
std::cout << "Have that 42 ... " << std::endl;
return 42;
}
public:
Stuff() {
x = 5;
}
};
struct StuffProxy {
// Make the layout public:
int x;
virtual int business();
};
int main() {
Stuff stuff;
void* thing = &stuff;
// Here's the nasty stuff
StuffProxy* stuffProxy = reinterpret_cast<StuffProxy*>(thing);
int* addrX = &(stuffProxy->x); // Get the address of x
std::cout << "x = " << *addrX << std::endl;
typedef int (Stuff::*StuffFunc)();
StuffFunc stuffFunc = (StuffFunc)(&StuffProxy::business);
std::cout << "business() = " << (stuff.*stuffFunc)() << std::endl;
}
Output:
x = 5
Have that 42 ...
business() = 42
Live Demo
The above works because it's guaranteed that class and struct will have the same layout in a c++ compilers implementation, with the only difference of the members visibility during compilation.
So if you have the layout of a class (e.g. from a header), and you are willing to maintain that over the lifetime of your project, you can provide such proxy like above to access the private stuff from a class.
To access the private member x:
1) Declare the function, that needs to access x, as a friend of the class.
2) Change access to public.
3) Write public getter or setter functions.
4) Change your design; Other classes should not know about member variables.
This may be compiler dependant.
I just made a char array from the pointer "thing"
char *array;
array = (char*)thing;
Then traverse that array until I found the private variables
int x = array[8];
In the comments to this answer, Koushik raised a very valid point.
Take the following:
union U
{
int x;
const T y;
};
(I choose T such that there is no common initial sequence of layout compatibility here, meaning only one member may be active at any given time per [C++11: 9.5/1].)
Since only one member may be "active" at any one time (made active by writing to it), and y cannot be written to after initialisation, isn't this rather pointless? I mean, y can only be read from until the first time x is written to, and at that only if y was the initialised member.
Is there some use case I'm missing? Or is this indeed a pretty pointless confluence of language features?
(This has been mentioned before)
Here's a contrived example of a reference-semantics type where you'd only want to grant const access to. The union is used in a variant-like data type returned from a "type-erasing" function.
#include <memory>
template<class T>
struct reference_semantics
{
public:
reference_semantics(T* p ) : m(p) {}
int observe() const { return *m; }
void change(T p) { *m = p; }
private:
T* m;
};
struct variant
{
enum T { INT, DOUBLE } type;
union U
{
reference_semantics<int> const i;
reference_semantics<double> const d;
U(int* p) : i(p) {}
U(double* p) : d(p) {}
} u;
};
#include <iostream>
std::ostream& operator<<(std::ostream& o, variant const& v)
{
switch(v.type)
{
case variant::INT:
return o << "INT: "<<v.u.i.observe();
case variant::DOUBLE:
return o << "DOUBLE: "<<v.u.d.observe();
}
}
#include <string>
variant type_erased_access(std::string name)
{
// imagine accesses to a map or so
static double dval = 42.21;
static int ival = 1729;
if(name == "Lightness") return { variant::DOUBLE, &dval };
else return { variant::INT, &ival };
}
int main()
{
variant v0( type_erased_access("Lightness") );
std::cout << v0 << "\n";
variant v1( type_erased_access("Darkness") );
std::cout << v1 << "\n";
}
Imagine now that instead of int and double, much larger data types are used, and that the reference_semantics data type actually provides more functionality than just returning the value.
It might even be possible that you want to return a reference_semantics<some_type> const for some arguments, but a plain int for others. In that case, your union might even have const and non-const members.
It does have uses:
1) For offering a const_cast-like technique. In a sense, x = const_cast<...>(y).
2) When dealing with templates, sometimes you need a const version of a data type so you match other parameter types.
(I've seen (1) used when programming against legacy interfaces).
Not using unions a lot, but this might be scenario:
#include <iostream>
class Accessor;
union Union
{
private:
friend class Accessor;
int write;
public:
const int read;
Union() : read(0) {}
};
class Accessor {
public:
static void apply(Union& u, int i) { u.write = i; }
};
int main() {
Union u;
// error: ‘int Union::write’ is private
// u.write = 1;
std::cout << u.read << '\n';
Accessor::apply(u, 1);
std::cout << u.read << '\n';
}
Note: From 9.5 Unions
Note: One special guarantee is made in order to simplify the use of
unions: If a standard-layout union contains several standard-layout
structs that share a common initial sequence (9.2), and if an object
of this standard-layout union type contains one of the standard-layout
structs, it is permitted to inspect the common initial sequence of any
of standard-layout struct members; see 9.2. — end note ]
If the union represents part of a result of some method/algorithm, then it could make sense. But in that case, I'd make both values const:
union T
{
const int x;
const int y;
};
Why can't a c++ class have same name for a function and a data member?
class demo{
public:
int size();
private:
int size;
};
int main(){
return 0;
}
C:\Users\S>g++ demo.c
demo.c:5:7: error: declaration of 'int demo::size'
demo.c:3:7: error: conflicts with previous declaration 'int demo::size()'
Suppose you want to take the address of the member-function size(), then you would write this:
auto address = &demo::size;
But it could be very well be the address of the member-data size as well. Ambiguous situation. Hence, it is disallowed by the language specification.
That is not to say that it was impossible for the C++ committee to come up with a solution, but I suppose there is no major gain in doing so. Hence, the Standard simply disallowed it, to keep things simple.
Also, the difference between member-data and member-function becomes less distinguishable visually if one declares the member function size() as:
typedef void fun_type();
struct demo
{
fun_type size; //It looks like a member-data, but it's a member-function
};
void demo::size() //define the member function
{
std::cout << "It is crazy!" << std::endl;
}
int main()
{
demo d;
d.size(); //call the function!
}
Output:
It is crazy!
See the online demo : http://ideone.com/ZjwyJ
Now if we can implement member functions as explained above, then it becomes too obvious even to the naked eye that you cannot add another member with same name as:
struct demo
{
fun_type size;
int size; //error - choose a different name for the member!
};
Wait That is not entirely correct, as the story is not finished yet. There is something less obvious I need to add here. You can add more than one member with same name:
typedef void fun_type0();
typedef void fun_type1(int a);
typedef void fun_type2(int a, int b);
struct demo
{
fun_type0 member; //ok
fun_type1 member; //ok
fun_type2 member; //ok
};
This is completely valid code, as each member is a function of different type, so you can define them as:
void demo::member()
{
std::cout << "member()" << std::endl;
}
void demo::member(int a)
{
std::cout << "member(" << a << ")" << std::endl;
}
void demo::member(int a, int b)
{
std::cout << "member(" << a << ", "<< b << ")" << std::endl;
}
Test code:
int main()
{
demo d;
d.member();
d.member(10);
d.member(200,300);
}
Output:
member()
member(10)
member(200, 300)
Online Demo : http://ideone.com/OM97Q
The conclusion...
You can add members with same name, as long as they're function of different types. This is enabled by a feature called member-function-overloading (or simple function-overloading)1.
1. Unfortunately, the language doesn't provide similar feature, say member-data-overloading, for member data, neither do the language provide cross-member-overloading (that allows member-data and member-function to have the same name — the case in the question).
So here a question naturally arises: do they not cause ambiguity problem? Yes, they do. But the point to be noted is that C++ committee came up with a solution to solve this ambiguity-problem, because they saw a huge gain in doing so, (in case of function-overloading).
But the case in the question remains ambiguous, as the committee didn't come up with a solution, as they didn't see any huge advantage in doing so (as noted before). Also, when I said "C++ committee came up with solution", I do NOT mean that the solution has been Standardized, I merely mean that they knew how the compilers can solve it, and how complex the solution would be.
because if you use size in your class somewhere then the compiler does not know what to do. It can be either the int-data-member or it can be the function-pointer. So the compiler is not able to seperate both kind
As an example (Not maybe the best but it might explain it visually):
class Size {
std::size_t size_;
public:
Size(std::size_t s = std::size_t() ) : size_(s){}
std::size_t operator()() const {
return size_;
}
void operator()(std::size_t s) {
size_ = s;
}
};
class Demo {
public:
Size size;
};
int main() {
Demo d;
d.size(10);
std::size_t size = d.size();
return 0;
}
Basically the variable could be callable as well. So there is no way for the compiler to know your intentions.
Of course this is defined by the language that it shall not be possible to have the same name as identifier within the same scope.