I recently had the problem that I needed some helper functions to return instances of different types, similar to std::make_pair. My syntax of choice for this was:
Event event(Trigger(...), []() { });
where ... was some simple parameter that created a different trigger type based on ...'s type (e.g., Time, UserInput, etc.).
In addition I wanted some predefined triggers that could be used directly, such as:
Event event(Trigger::OnInit, []() { });
I found that defining a class and instance named Trigger allowed me to support both syntaxes:
static const struct Trigger {
static const OnceTrigger OnInit;
TimeTrigger operator()(Time const &) const;
UserTrigger operator()(UserInput const &) const;
} Trigger;
Notice the identically named type and instance names.
This works in both GCC and MSVC, but I am wondering if and how valid this is according to the standard. Is it "luck" that both compilers support this? Or is name lookup defined such that this is guaranteed to work on all compilers?
In the function call syntax Trigger(...), the class is hidden by the instance per 3.3.10:
2 - 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 the qualified name lookup syntax Trigger::OnInit, the class is visible per 3.4.3:
1 - [...] lookup of the name preceding [the] :: considers only namespaces, types, and templates whose specializations are types.
Indeed, the standard has an example which demonstrates how qualified name lookup is not subject to hiding of type names:
class A {
public:
static int n;
};
int main() {
int A;
A::n = 42; // OK
A b; // ill-formed: A does not name a type
}
So your code is fine per the standard. (Whether it's a good style is another matter entirely!)
Being able to name a structure (or class in C++) type the same as an instance of that structure is brought in from C, and it's because structure-names are in a separate namespace (not in the sense of C++ namespace though) compared to variable-names.
Related
I wrote following simple program & compiled it on gcc compiler
#include <stdio.h>
typedef int i;
void foo()
{
struct i {i i;} i;
i.i = 3;
printf("%i\n", i.i);
}
int main() { foo(); }
It compiles & runs fine in C.(See live demo here) But it fails in compilation in C++. C++ compiler gives following error messages.
prog.cc: In function 'void foo()':
prog.cc:5:17: error: field 'i' has incomplete type 'foo()::i'
struct i {i i;} i;
^
prog.cc:5:12: note: definition of 'struct foo()::i' is not complete until the closing brace
struct i {i i;} i;
See live demo here
I couldn't find rules regarding this in C & C++ standards. Why it compiles fine in C but not in C++ ? What does the standard says about this ? I very well know that C & C++ are different languages having different rules but I am curious to know about exact rules.
The difference between C and C++ is the following. In C the data member i is considered as having type int because if you wanted that it had type struct i then you have to write struct i i specifying the keyword struct before i.
Structure tags are in their own namespace compared with the namespace of other variables.
According to the C Standard (6.2.3 Name spaces of identifiers)
1 If more than one declaration of a particular identifier is visible
at any point in a translation unit, the syntactic context
disambiguates uses that refer to different entities. Thus, there are
separate name spaces for various categories of identifiers, as
follows:
— label names (disambiguated by the syntax of the label declaration
and use);
— the tags of structures, unions, and enumerations (disambiguated by
following any32) of the keywords struct, union, or enum);
— the members of structures or unions; each structure or union has a
separate name space for its members (disambiguated by the type of the
expression used to access the member via the . or -> operator);
— all other identifiers, called ordinary identifiers (declared in
ordinary declarators or as enumeration constants).
As for C++ then inside the structure definition the name of the structure hides the name of the typedef and the compiler issues the error. In C++ there is separate class scope.
For example in C++ (3.4 Name lookup) there is written
3 The injected-class-name of a class (Clause 9) is also considered
to be a member of that class for the purposes of name hiding and
lookup.
and (3.4.1 Unqualified name lookup)
7 A name used in the definition of a class X outside of a member
function body or nested class definition29 shall be declared in one of
the following ways: — before its use in class X or be a member of
a base class of X (10.2), or ...
Thus the injected name of the class hides the typedef name within the class definition.
Take into account that outside the class definition the name of the class can be hidden by the same name of an object. Thus if you want to declare an object of the class in that scope you have to use its elaborated name like
int i;
struct i {};
//...
struct i obj;
Consider the following code:
struct A {
int propose();
};
struct A1 : A {
int propose(int);
using A::propose;
};
struct B1 : A1 {
protected:
using A1::propose;
public:
using A::propose;
};
int main() {
B1().propose();
}
Let's compile this: g++ -std=c++11 main.cpp.
I'm getting the following compiler error using GNU 4.8.1:
main.cpp: In function 'int main()':
main.cpp:2:9: error: 'int A::propose()' is inaccessible
int propose();
^
main.cpp:18:18: error: within this context
B1().propose();
However, this code compiles in AppleClang 6.0.0.6000056.
I understand that there is no need for the using in B1, (in my code was necessary, but I had 1 using too much by mistake). In any case, why Clang compiles it? Is this expected?
In [namespace.udecl], we have:
When a using-declaration brings names from a base class into a derived class scope, member functions and
member function templates in the derived class override and/or hide member functions and member function
templates with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (if any) in a
base class (rather than conflicting).
The standard explicitly says that names brought in will not conflict with names in a base class. But it doesn't say anything about bringing in conflicting names.
The section also says:
A using-declaration is a declaration and can therefore be used repeatedly where (and only where) multiple
declarations are allowed. [ Example:
struct B {
int i;
};
struct X : B {
using B::i;
using B::i; // error: double member declaration
};
—end example ]
And interestingly, in the following example it's GCC that happily compiles it (and prints A) while Clang allows the construction of a C but rejects the call to foo as ambiguous:
struct A {
void foo() { std::cout << "A\n"; }
};
struct B {
void foo() { std::cout << "B\n"; }
};
struct C : A, B {
using A::foo;
using B::foo;
};
int main()
{
C{}.foo();
return 0;
}
So the short answer is - I suspect this is underspecified in the standard and that both compilers are doing acceptable things. I would just avoid writing this sort of code for general sanity.
The declaration is legal.
Calling it is legal and should work anywhere, and it can only be called from the class and derived classes, and it can be called from within any class. You'll note that this makes little sense.
There are no rules that ban that construct in declarations (importing the name twice from two different base classes with the same signature), and it is even used in "real" code where the derived class goes and hides the name after they are imported.
If you don't hide it, you are in the strange situation where the same function A::propose is both protected and public at the same time, as it is named twice (legally) in the same scope with different access control. This is ... unusual.
If you are within a class, a sub-clause says you can use it:
[class.access.base]/5.1
A member m is accessible at the point R when named in class N if — (5.1) m as a member of N is public
and propose is clearly public. (it is also protected but we don't have to keep reading for that case!)
Elsewhere, we have a contradiction. You are told you can use it everywhere without restriction [class.access]/1(3). And you are told that you can only use it in certain circumstances [class.access]/1(2).
I am uncertain how to resolve that ambiguity.
The rest of the logic train:
In [namespace.udecl]/10 we have:
A using-declaration is a declaration and can therefore be used repeatedly where (and only where) multiple declarations are allowed.
And [namespace.udecl]/13:
Since a using-declaration is a declaration, the restrictions on declarations of the same name in the same declarative region
so each of those using X::propose; are declarations.
[basic.scope] has no applicable restrictions on two functions of the same name in a scope, other than [basic.scope.class]/1(3) which states that if reordering of declarations changes the program, the program is ill-formed. So we cannot say that the later one wins.
Two declarations of member functions in the same scope are legal under [basic.scope]. However, under [over], there are restrictions on two member functions with the same name.
[over]/1 states:
When two or more different declarations are specified for a single name in the same scope, that name is said to be overloaded
And there are some restrictions on overloading. This is what usually prevents
struct foo {
int method();
int method();
};
from being legal. However:
[over.load]/1 states:
Not all function declarations can be overloaded. Those that cannot be overloaded are specified here. A program is ill-formed if it contains two such non-overloadable declarations in the same scope. [Note: This
restriction applies to explicit declarations in a scope, and between such declarations and declarations made through a using-declaration (7.3.3). It does not apply to sets of functions fabricated as a result of name lookup (e.g., because of using-directives) or overload resolution (e.g., for operator functions). —end note
the note explicitly permits symbols introduced via two using-declarations from being considered by the overloading restrictions! The rules only apply to two explicit declarations within the scope, or between an explicit declaration within the scope and a using declaration.
There are zero restrictions on two using-declarations. They can have the same name, and their signatures can conflict as much as you'd like.
This is useful, because usually you can go and then hide their declaration (with a declaration in the derived class), and nothing goes wrong [namespace.udecl]/15:
When a using-declaration brings names from a base class into a derived class scope, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting).
However, this is not done here. We then call the method. Overload resolution occurs.
See [namespace.udecl]/16:
For the purpose of overload resolution, the functions which are introduced by a
using-declaration into a derived class will be treated as though they were members of the derived class. In particular, the implicit this parameter shall be treated as if it were a pointer to the derived class rather than to the base class. This has no effect on the type of the function, and in all other respects the function remains a member of
the base class.
So we have to treat them as if they are members of the derived class for the purpose of overload resolution. But there are still 3 declarations here:
protected:
int A::propose(); // X
int A1::propose(int); // Y
public:
int A::propose(); // Z
Thus the call to B1().propose() considers all 3 declarations. Both X and Z are equal. They, however, refer to the same function, and overload resolution states there is an ambiguity if two different functions are selected. So the result is not ambiguous. There may be access control violations, or not, depending on how you read the standard.
[over.match]/3
If a best viable function exists and is unique, overload resolution succeeds and produces it as the result. Otherwise overload resolution fails and the invocation is ill-formed. When overload resolution succeeds, and the best viable function is not accessible (Clause 11) in the context in which it is used, the program is ill-formed.
I am reading this Stack Overflow question, and I added a constructor to the code from that question as the follwing,
class Foo {
struct Bar {
int i;
Bar(int a = 5) :i(a) {};
};
public:
Bar Baz() { return Bar(); }
};
int main() {
Foo f;
// Foo::Bar b = f.Baz(); // error
auto b = f.Baz(); // ok
std::cout <<"b.i="<< b.i<<endl;
return 0;
}
The code outputs b.i=5. In that question it concludes that the name of the private is not accessible but the type is. So what's the difference between type and name, generally?
And say I have two specific scenarios.
What's the difference between the following two declarations? Why can I get the output b.i=5 from auto b = f.Baz();?
Foo::Bar b = f.Baz();
auto b = f.Baz();
If I add typedef Bar B; in the public part of Foo, what is the difference between the following?
Foo::Bar b = f.Baz();
Foo::B b = f.Baz();
If there a difference between scenario 1 and 2?
What is the difference between type and name
A type has none, one or several names. Typedef and alias are simply means of creating a new name for a type.
public and private keywords relate to names not to the underlying types or members.
In order to explicitly declare an object of a particular type you need a name for that type. auto doesn't need this. If you for example use an unnamed class as a return type, this class has no name but auto can still be used on it.
An type will always have at most one 'true name'. Even when using it through a typedef or alias, the compiler uses it under this name (or actually the raw version of this name). So:
class A {};
typedef A B;
std::cout << typeid(B).name();
Prints "class A". An unnamed object cannot be given a 'true name'. However, when using typedef and decltype. A new name can be created. If this name is then used to create objects. typeid().name will print the newly assigned name. If the object wasn't unnamed to start with the 'true name' name will be printed.
The scenarios:
The difference is that in the first you are using a privately declared name. Which is illegal. This has to do with how the different ways of type deduction work. As Scott Meyers explains here. Since a public function call provides this type, the return type is public. However, Bar on itself is not public. It's a small difference, but that is the reason.
This simply is a decision that has been made in the design. It makes sense, sometimes you only want a struct to be used when you return it.
The same goes here. There is no difference, however Foo::Bar simply is inaccessible.
Edit
Can you give an example that type has none names? is the unnamed union in the above comment a example of this?
As described here I use a lambda function as follows:
auto f = [] () -> struct {int x, y ; } { return { 99, 101 } ; } ;
Without using auto or decltype there would be no way of creating variable f. Since it's type has no name. Another example of a type without a name.
struct foo
{
struct{
int x;
int y;
} memberVar;
};
Would allow you to do the following:
foo bar;
auto baz = bar.memberVar;
std::cout << baz.x;
Which results in a bunch of initialized stuff of course, but you get the idea:). The type of memberVar here is unnamed. Making it impossible to define baz explicitly.
And is int considered to be a name for type of int?
int is a bit special, being a fundamental type. 'int' indeed is the name of the type int. But it's by no means the only name, int32_t, for example is another name for the exact same type on most compilers(on other systems int16_t is equivalent to int).
std::cout << typeid(int32_t).name();
Prints "int".
Notes:
I've refrained from using alias as an indicator for other names of an object, since this might cause confusion with the alias keyword.
Most of this I have gathered from experience. So I might have missed some bits.
By lack for a better word i have used the expression 'true name'. If anybody knows the official or a better word for this i'd be happy to hear it:).
[Some standardese ahead]
Let's agree that auto deduction works in the same way as template argument deduction:
[dcl.spec.auto]/p7
If the placeholder is the auto
type-specifier, the deduced type is determined using the rules for template argument deduction
Templates are subject to the two-phase lookup during compilation. Access control is applied to name lookup in the first phase
[basic.lookup]/p1
Overload resolution (13.3) takes place after name lookup has succeeded. The access rules (Clause 11) are considered only once name lookup and function overload resolution (if applicable) have succeeded. Only after name lookup, function overload resolution (if applicable) and access checking have succeeded are the attributes introduced by the name’s declaration used further in expression processing
auto and decltype(auto) are usually a placeholder for a deduced type, and it is true that [temp.arg]/p3 says
The name of a template-argument shall be accessible at the point where it is used as a template-argument
but names aren't involved here, only the types. Access control applies to names, a type can be mapped to 0, 1 or multiple names and that's what you're dealing with when using auto in the code above: it is semantically equivalent to the semantics of template deduction and this is by design.
[class.access]/p4
Access control is applied uniformly to all names, whether the names are referred to from declarations or
expressions. [...] The accessibility
of the entity referred to by the typedef is not considered. For example
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
}
To convince yourself of the following take a look at the same code with template argument deduction involved (conceptually equivalent to the auto version)
template<class T>
T deduce(T t) {
return t;
}
class Foo {
struct Bar{
int i;
Bar(int a = 5):i(a){};
};
public:
Bar *getB() { return new Bar(5); } // Leaks, doesn't matter for clarity's sake
};
int main() {
Foo f;
std::cout <<"b.i="<< deduce(f.getB())->i <<std::endl; // Prints 'b.i=5'
return 0;
}
Live example
In the code above names aren't involved and thus access control doesn't apply. Types are indeed involved.
The semantics of auto is like implicit template deduction (the normative wording also directly refers to it).
Someone else had this doubt before.
Now for the answers:
Case 1 is easy to agree with if you consider that the caller has no access to the name Foo::Bar.
Case 2 exposes the name to the caller as well, so if you use the typedef'd name your code will happily compile.
The question you link explains a lot but as a supplement to what is being written there...
The main difference is that in the second line auto b=... you let the compiler deduce the type of the expression. You can't specify the type, as the name of the type is hidden. The type though is usable (at least from the compiler)
You expose the name of the type publicly so it can be used.
This is a very nice answer https://stackoverflow.com/a/13532882/3037915
To try to answer the question in the header, you may consider type as a shape and the name of the type as the name you use to refer to a particular shape. Even if the name of the "shape" is hidden, the shape still exists and can be used.
#include <iostream>
using namespace std;
struct test
{
test(){cout<<"class"<<endl;}
};
void test(){cout<<"function"<<endl;}
int main()
{
test();
return 0;
}
Output:
function
(VS2013 ang gcc 4.8.1)
Why function is selected? Isn't it ambiguity?
This is called name hiding and described in
3.3 Scope [basic.scope]
3.3.1 Declarative regions and scopes [basic.scope.declarative]
4) Given a set of declarations in a single declarative region, each of
which specifies the same unqualified name, — they shall all refer to
the same entity, or all refer to functions and function templates; or
— exactly one declaration shall declare a class name or enumeration
name that is not a typedef name and the other declarations shall all
refer to the same variable or enumerator, or all refer to functions
and function templates; in this case the class name or enumeration
name is hidden (3.3.10). [...]
emphasis mine.
Note that changing the order of declaration doesn't affect the outcome:
void test(){cout<<"function"<<endl;}
struct test
{
test(){cout<<"class"<<endl;}
};
int main()
{
test();
return 0;
}
still prints out function.
In case it isn't obvious, don't do this :)
From N3485 §3.3.10 [basic.scope.hiding]/2:
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.
Therefore, the function takes precedence over the class.
As mentioned in the comments, the class is still accessible via the class or struct keyword. If the class took precedence, the function would be unreachable.
I'm not certain either of the previous responses are the "why" for your particular instance.
Don't get me wrong; They are true and accurate.
I just think it's simpler.
In your example, you never instantiate the struct.
In other words, you declared it, but you never used it.
Since you never referenced it, it is never called.
Name precedence and such don't really apply here, since you never instantiated the struct.
Hope this helps,
-john
$10.2/4- "[ Note: Looking up a name in
an elaborated-type-specifier (3.4.4)
or base-specifier (Clause 10), for
instance, ignores all nontype
declarations, while looking up a name
in a nested-name-specifier (3.4.3)
ignores function, variable, and
enumerator declarations."
I have found this statement to be very confusing in this section while describing about name lookup.
void S(){}
struct S{
S(){cout << 1;}
void f(){}
static const int x = 0;
};
int main(){
struct S *p = new struct ::S; // here ::S refers to type
p->::S::f();
S::x; // base specifier, ignores the function declaration 'S'
::S(); // nested name specifier, ignores the struct declaration 'S'.
delete p;
}
My questions:
Is my understanding of the rules correct?
Why ::S on the line doing new treated automatically to mean struct S, whereas in the last line ::S means the functions S in the global namespace.
Does this point to an ambiguity in the documentation, or is it yet another day for me to stay away from C++ Standard document?
Q1: I think so.
Q2: Compatibility with C. When you declare a struct in C, the tag name is just that, a tag name. To be able to use it in a standalone way, you need a typedef. In C++ you don't need the typedef, that makes live easier. But C++ rules have been complicated by the need to be able to import already existing C headers which "overloaded" the tag name with a function name. The canonical example of that is the Unix stat() function which uses a struct stat* as argument.
Q3: Standard reading is usually quite difficult... you need to already know that there is no place elsewhere modifying what you are reading. It isn't strange that people knowing how to do that are language lawyer...
You are mistaken about the second comment. In S::x, the S is a name in a nested name specifier. What the Standard refers to with "base-specifier" is the following
namespace B { struct X { }; void X() }
struct A : B::X { }; // B::X is a base-specifier
You are also not correct about this:
::S(); // nested name specifier, ignores the struct declaration 'S'.`
That code calls the function not because ::S would be a nested-name-specifier (it isn't a nested-name-specifier!), but because function names hide class or enumeration names if both the function and the class/enumeration are declared in the same scope.
FWIW, the following code would be equally valid for line 2 of your main
p->S::f();
What's important is that S preceedes a ::, which makes lookup ignore the function. That you put :: before S has no effect in your case.