In C++ consider the grammar rule:
member-access-expression: LHS member-access-operator RHS
(op is .)
and
LHS=unqualified id-expression e.g. that references an instance variable.
RHS=qualified id-expression (with at least one nested identifier)
example: a.b::c
If that can ever pass the semantic check, what situation would it be ?
The following experiment:
struct B{};
struct A
{
B b;
};
int main()
{
A a;
a.b::c;
}
returns
'b' is not a class, namespace, or enumeration
a.b::c;
^
(demo)
This tends to hint to me that there can't be any legal case of a qualified-id on the right of a member access.
A very simple example is if you want to call a member function of a parent class:
struct A {
void f();
};
struct B: A {
void f();
};
B b;
b.A::f();
One use case is accessing members of an enum within some struct A by using an instance of A (rather than using the enum directly via A::b::c):
struct A {
enum class b { c }; // can be unscoped as well
};
A a;
a.b::c; // Access to enum value c - similarly, A::b::c would work
Here's a trivial example:
struct A {
void f() {}
};
int main()
{
A a;
a.A::f();
}
A::f() is a qualified version of the name for the function f that's a member of A. You can use it in member access just like the "short" (or unqualified) name.
In fact, one might argue that every time you write a.f(), that's a shortcut for a.A::f() (with the A:: part being taken automatically from decltype(a)).
There's nothing magic about this, though it's unusual to see the construct outside of the sort of scenarios the other answerers demonstrated, because in this example it's redundant.
Related
I made this simple class, which still is playing with my mind:
class A {
private:
class B {};
public:
B getB() {
return B();
};
};
As of C++03, this class compiles fine, but there is just no nice looking way to assign the result of getB() to an lvalue, in the sense that:
A::B b = A().getB();
Does not compile.
I got it by using an intermediate template, in this fashion:
template <typename T>
struct HideType {
typedef T type;
};
HideType<A::B>::type b = A().getB();
But this looks just terrible, for this simple task of getting an A::B lvalue variable.
This is not true anymore as of C++11, or at least it is not with gcc. This code is still not valid:
A::B b = A().getB();
But this is valid:
auto b = A().getB();
Is there a loophole in the standard respect to this?
From Standard, Clause 11 (Member access control):
A member of a class can be
— private; that is, its name can be used only by members and friends of the class in which it is declared.
— protected; that is, its name can be used only by members and friends of the class in which it is
declared, by classes derived from that class, and by their friends (see 11.4).
— public; that is, its name can be used anywhere without access restriction.
So access control is applied to names.
In
auto b = A().getB();
you don't use private names, therefore it's legal, according to Standard
The fact why A::B b = A().getB() doesn't work is because B is a private class member of A. If you make it public then your code will compile. It works with auto because auto just checks the type of the object assigned to it without needing to call the constructor of the object (just like declval). So it assigns b with the return type of getB present in class A. You can change your code in the following way too :
decltype( declval<A>().getB() ) b = A().getB();
( If declval is new to you then I must tell you that it would return an rvalue of the return type of the function (here getB whose return type is B) of a class (here A) without calling the constructor of the class ! (This should however be used with functions like decltype and sizeof only.) So it prevents the overhead of creating a class object and then using its function. )
Now according to me, I don't think this is a loophole in the standard rather I feel the loophole has been removed ! It's obvious from your own code, see the function getB. How difficult it is to instantiate an object of B because it's defined in private ! In such a case working with B becomes difficult. The idea behind this is that the name of the type (ie B) in the class A is inaccessible but the type is still usable which is why you can get an object of B. You can understand the use of auto if you understand the this template code :-
#include <iostream>
#include <type_traits> // for std::is_same
using namespace std;
class A
{
class B
{};
public:
B getB()
{
return B();
}
};
template<typename T>
void check (T b)
{
cout<<boolalpha;
is_same<decltype( declval<A>().getB() ), T> x; // checks if T & B are of same type
cout<<x.value<<'\n';
}
int main()
{
A obj;
check (obj.getB());
return 0;
}
Output :-
true
As the template could identify B, hence auto too identifies B.
It seems, there was such a defect in a draft of the Standard, but it had been corrected by WP 1170.
Probably, there is a compiler bug. The declaration auto b = A().getB(); involves template argument deduction for the auto type-specifier, so according to the C++11 Standard it should be ill-formed, because that type deduction fails.
I made this simple class, which still is playing with my mind:
class A {
private:
class B {};
public:
B getB() {
return B();
};
};
As of C++03, this class compiles fine, but there is just no nice looking way to assign the result of getB() to an lvalue, in the sense that:
A::B b = A().getB();
Does not compile.
I got it by using an intermediate template, in this fashion:
template <typename T>
struct HideType {
typedef T type;
};
HideType<A::B>::type b = A().getB();
But this looks just terrible, for this simple task of getting an A::B lvalue variable.
This is not true anymore as of C++11, or at least it is not with gcc. This code is still not valid:
A::B b = A().getB();
But this is valid:
auto b = A().getB();
Is there a loophole in the standard respect to this?
From Standard, Clause 11 (Member access control):
A member of a class can be
— private; that is, its name can be used only by members and friends of the class in which it is declared.
— protected; that is, its name can be used only by members and friends of the class in which it is
declared, by classes derived from that class, and by their friends (see 11.4).
— public; that is, its name can be used anywhere without access restriction.
So access control is applied to names.
In
auto b = A().getB();
you don't use private names, therefore it's legal, according to Standard
The fact why A::B b = A().getB() doesn't work is because B is a private class member of A. If you make it public then your code will compile. It works with auto because auto just checks the type of the object assigned to it without needing to call the constructor of the object (just like declval). So it assigns b with the return type of getB present in class A. You can change your code in the following way too :
decltype( declval<A>().getB() ) b = A().getB();
( If declval is new to you then I must tell you that it would return an rvalue of the return type of the function (here getB whose return type is B) of a class (here A) without calling the constructor of the class ! (This should however be used with functions like decltype and sizeof only.) So it prevents the overhead of creating a class object and then using its function. )
Now according to me, I don't think this is a loophole in the standard rather I feel the loophole has been removed ! It's obvious from your own code, see the function getB. How difficult it is to instantiate an object of B because it's defined in private ! In such a case working with B becomes difficult. The idea behind this is that the name of the type (ie B) in the class A is inaccessible but the type is still usable which is why you can get an object of B. You can understand the use of auto if you understand the this template code :-
#include <iostream>
#include <type_traits> // for std::is_same
using namespace std;
class A
{
class B
{};
public:
B getB()
{
return B();
}
};
template<typename T>
void check (T b)
{
cout<<boolalpha;
is_same<decltype( declval<A>().getB() ), T> x; // checks if T & B are of same type
cout<<x.value<<'\n';
}
int main()
{
A obj;
check (obj.getB());
return 0;
}
Output :-
true
As the template could identify B, hence auto too identifies B.
It seems, there was such a defect in a draft of the Standard, but it had been corrected by WP 1170.
Probably, there is a compiler bug. The declaration auto b = A().getB(); involves template argument deduction for the auto type-specifier, so according to the C++11 Standard it should be ill-formed, because that type deduction fails.
Please consider the following code:
struct A
{
void f()
{
}
};
struct B1 : A
{
};
struct B2 : A
{
};
struct C : B1, B2
{
void f() // works
{
B1::f();
}
//using B1::f; // does not work
//using B1::A::f; // does not work as well
};
int main()
{
C c;
c.f();
return 0;
}
I kindly ask you not to copy paste a standard reply on how to solve the diamond problem ("use virtual inheritance"). What I am asking here is why doesn't a using-declaration work in this case. The exact compiler error is:
In function 'int main()':
prog.cpp:31:6: error: 'A' is an ambiguous base of 'C'
c.f();
I got the impression a using-declaration should work from this example:
struct A
{
void f()
{
}
};
struct B
{
void f()
{
}
};
struct C : A, B
{
using A::f;
};
int main()
{
C c;
c.f(); // will call A::f
return 0;
}
Someone else can find the standard quote but I'm going to explain conceptually.
It doesn't work because a using-declaration only affects name lookup.
Your using-declaration causes name lookup to succeed where it would otherwise fail, that is, it tells the compiler where to find the function f. But it does not tell it which A subobject f acts on, that is, which one will be passed as the implicit this parameter when f is called.
There is only a single function A::f even though there are two A subobjects of C, and it takes an implicit this argument of type A*. In order to call it on a C object, C* must be implicitly converted to A*. This is always ambiguous, and is not affected by any using-declarations.
(This makes more sense if you put data members inside A. Then C would have two of each such data member. When f is called, if it accesses data members, does it access the ones in the A subobject inherited from B1, or the ones in the A subobject inherited from B2?)
There's a note in [namespace.udecl]/p17 that addresses this situation directly:
[ Note: Because a using-declaration designates a base class member
(and not a member subobject or a member function of a base class
subobject), a using-declaration cannot be used to resolve inherited
member ambiguities. For example,
struct A { int x(); };
struct B : A { };
struct C : A {
using A::x;
int x(int);
};
struct D : B, C {
using C::x;
int x(double);
};
int f(D* d) {
return d->x(); // ambiguous: B::x or C::x
}
—end note ]
In addition to T.C.'s answer, I'd like to add that the name lookup in derived class is explained in the standard pretty much in detail in section 10.2.
Here what is said about processing of using-declarations :
10.2/3: The lookup set (...) consists of two component sets: the declaration set, a set of members named f; and the subobject set, a set of subobjects where declarations of these members (possibly including
using-declarations) were found. In the declaration set, using-declarations are replaced by the members they designate, and type declarations (including
injected-class-names) are replaced by the types they designate.
So when you try to declare in struct C
using B1::f; // you hope to make clear that B1::f is to be used
according to the lookup rules, your compiler nevertheless finds the possible candidates: B1::f and B2::f so that it's still ambiguous.
The following code compiles in C++
struct foo
{
int a, b;
};
struct foo foo()
{
struct foo a;
return a;
}
int main(void) {
foo();
return 0;
}
Is it supposed to be allowed to have a struct and a function with the same name ?
Since it compiles I then go on and try to declare an object of type foo. Is there a way? It seems impossible to do :
foo a; // error: expected ‘;’ before ‘a’
foo a{}; // error: expected ‘;’ before ‘a’
foo a(); // most vexing parse would kick in any way
Yes, this is allowed we can see this by going to draft C++ standard section 3.3.10 Name hiding paragraph 2 and it says (emphasis mine):
A class name (9.1) or enumeration name (7.2) can be hidden by the name of a variable, data member, function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data member, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is visible.
In this case using struct in the declaration would fix your issue:
struct foo a;
Usually a bad habbit to do something like that. I would name it foo_s or whatever to distinguish it from the function. Other than that, there isn't really a way of doing it.
In C this is possible, since it requires
struct foo
instead of just
foo
as the type name (unless it is typedef'd)
Yes, you can, but it's a really bad pattern to get into.
struct foo
{
};
foo foo(foo& f)
{
return f;
}
int main()
{
struct foo f;
foo(f);
return 0;
}
See livedemo: http://ideone.com/kRK19f
The trick was to specify struct foo when we wanted to get at the type. Note that, until you create this ambiguity, it's actually not necessary to keep saying struct, this isn't C (as in the line foo foo(foo& f)).
Most developers choose a camel casing pattern, e.g they use an upper case letter to distinguish type names and a lowercase letter for a function name:
struct Foo
{
};
Foo foo(); // no ambiguity.
Back in Microsoft's prime, many Windows developers acquired the habit of prefixing struct/class definitions, the definition of a class of thing if you will, with a capital C
struct CFoo
{
};
Now, even if you want to use upper-case first letters for your function names, there is no ambiguity.
Just do it like you would in C, using:
struct foo a;
You might even initialise it like this:
struct foo a{};
struct foo a = {0};
A workaround would be using a typedef, thus avoiding any ambiguity and other difficulties:
typedef struct foo s_foo;
From The.C++.Programming.Language.Special.Edition $A.8:
To preserve C compatibility, a class and a non-class of the same name can be declared in the same
scope ($5.7). For example:
struct stat { /* ... */ };
int stat(char * name, struct stat * buf);
In this case, the plain name (stat) is the name of the non-class. The class must be referred to using
a class-key prefix .
Sometimes, C++'s notion of privacy just baffles me :-)
class Foo
{
struct Bar;
Bar* p;
public:
Bar* operator->() const
{
return p;
}
};
struct Foo::Bar
{
void baz()
{
std::cout << "inside baz\n";
}
};
int main()
{
Foo::Bar b; // error: 'struct Foo::Bar' is private within this context
Foo f;
f->baz(); // fine
}
Since Foo::Bar is private, I cannot declare b in main. Yet I can call methods from Foo::Bar just fine. Why the hell is this allowed? Was that an accident or by design?
Oh wait, it gets better:
Foo f;
auto x = f.operator->(); // :-)
x->baz();
Even though I am not allowed to name the type Foo::Bar, it works just fine with auto...
Noah wrote:
type names defined within a class definition cannot be used outside their class without qualification.
Just for fun, here is how you can get at the type from outside:
#include <type_traits>
const Foo some_foo();
typedef typename std::remove_pointer<decltype( some_foo().operator->() )>::type Foo_Bar;
Trying to find anything in the standard that would spell it out in detail but I can't. The only thing I can find is 9.9:
Type names obey exactly the same scope rules as other names. In particular, type names defined within a class definition cannot be used outside their class without qualification.
Essentially, the name of Foo::Bar is private to Foo, not the definition. Thus you can use Bars outside of Foo, you just can't refer to them by type since that name is private.
The name lookup rules for members would also seem to have some effect on this. I don't see anything that specifically references "nested class" and thus they wouldn't be allowed to (if my lack of finding anything in fact is because it's not there).
I can't provide a full answer, but maybe a starting point. The C++ 1998 specification includes the following code example under paragraph 11.3 [class.access] (p. 175):
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
}
In this example, a private type is "published" through a public typedef. Although it's not the same thing as publishing a type through a member function signature, it's similar.
I think this is by design. You cannot explicitly create instance of Foo::Bar but it could be returned from member functions and then you could pass it to other member functions. This lets you to hide implementation details of your class.