Question
In C++ we use double colon (::
) to access members of namespace, use dot (.
) to access members of class/structure and use arrow (->
) to access members of class/structure via pointer.
Wouldn't it be possible to use just dot (.
)? E.g. my_namespace.my_class.my_static_pointer.my_member
. Why are separate lexemes used? Would there be any problems with syntax, if only dot (.
) were used for all three cases?
Answers
Answer #1
As observed by Jules it's a fact that early C++ implementations (CFront pre-1.0) had a dot for scope identification.
A dot was also used in C with Classes (1980). Indeed this is a simple snippet from Classes: An Abstract Data Type Facility for the C Language 1:
class stack {
char s[SIZE]; /* array of characters */
char * min; /* pointer to bottom of stack */
char * top; /* pointer to top of stack */
char * max; /* pointer to top of allocated space */
void new(); /* initialization function (constructor) */
public:
void push(char);
char pop();
};
char stack.pop()
{
if (top <= min) error("stack underflow");
return *(−−top);
}
(the code was an example of how member functions were typically defined "elsewhere")
The ::
was one of the additions to C with Classes introduced to produce C++.
The reason is given by Stroustrup himself:
In C with Classes, a dot was used to express membership of a class as well as expressing selection of a member of a particular object.
This had been the cause of some minor confusion and could also be used to construct ambiguous examples. To alleviate this,
::
was introduced to mean membership of class and.
was retained exclusively for membership of object
(A History of C++: 1979−1991 [2] page 21 - § 3.3.1)
Bjarne Stroustrup: "Classes: An Abstract Data Type Facility for the C Language" - Bell Laboratories Computer Science Technical Report CSTR−84. April 1980.
Bjarne Stroustrup: "A History of C++: 1979−1991" - AT&T Bell Laboratories Murray Hill, New Jersey 07974.
Comment
It is still unclear what those minor confusion and ambiguous examples are.
Answer #2
Moreover it's true that
they do different things, so they might as well look different
indeed
In
N::m
neitherN
norm
are expressions with values;N
andm
are names known to the compiler and::
performs a (compile time) scope resolution rather than an expression evaluation. One could imagine allowing overloading of x::y where x is an object rather than a namespace or a class, but that would - contrary to first appearances - involve introducing new syntax (to allowexpr::expr
). It is not obvious what benefits such a complication would bring.Operator
.
(dot) could in principle be overloaded using the same technique as used for->
.
(Bjarne Stroustrup's C++ Style and Technique FAQ)
Answer #3
Because someone in the C++ standards committee thought that it was a good idea to allow this code to work:
struct foo
{
int blah;
};
struct thingy
{
int data;
};
struct bar : public foo
{
thingy foo;
};
int main()
{
bar test;
test.foo.data = 5;
test.foo::blah = 10;
return 0;
}
Basically, it allows a member variable and a derived class type to have the same name. I have no idea what someone was smoking when they thought that this was important. But there it is.
When the compiler sees .
, it knows that the thing to the left must be an object. When it sees ::
, it must be a typename or namespace (or nothing, indicating the global namespace). That's how it resolves this ambiguity.
Comment
"test.(foo.blah) = 10
" could be used in such ambiguous cases.