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;
Related
Is it valid C++ ?
#include <iostream>
class Test {
struct Inner {
};
public:
using Inner = struct Inner; // Alias with same name as type
};
int main(int argc, const char * argv[]) {
static_assert(std::is_pod<Test::Inner>::value, "");
return 0;
}
Compile fine with clang but not with GCC / Visual C++ ("Inner is private..." error message)
GCC and Visual C++ are correct.
Indeed you can use using to in effect change the access of a member, e.g.
using Inner_ = Inner;
with
static_assert(std::is_pod<Test::Inner_>::value, "");
in the function.
But in the case where the type alias has the same name as the member, C++ requires that the scope resolution operator looks up the member. So in your case Test::Inner refers to the actual member rather than to the using and compilation should therefore fail as it's private.
See https://en.cppreference.com/w/cpp/language/qualified_lookup, and in particular
Qualified lookup within the scope of a namespace N first considers all
declarations that are located in N and all declarations that are
located in the inline namespace members of N (and, transitively, in
their inline namespace members). If there are no declarations in that
set then it considers declarations in all namespaces named by
using-directives found in N and in all transitive inline namespace
members of N
P1787R6: Declarations and where to find them, merged into C++23 draft, seems to favor Clang's behavior:
[basic.lookup]
In certain contexts, only certain kinds of declarations are included. After any such restriction, any declarations of classes or enumerations are discarded if any other declarations are found. [Note: A type (but not a typedef-name or template) is therefore hidden by any other entity in its scope. — end note] However, if a lookup is type-only, only declarations of types and templates whose specializations are types are considered; furthermore, if declarations of a typedef-name and of the type to which it refers are found, the declaration of the typedef-name is discarded instead of the type declaration.
So the declaration of struct Inner is discarded, because the alias-declaration is found. (One can put Inner into type-only context — Test::struct Inner — and it will refer to the struct Inner declaration, per the second part of the paragraph).
This is my second investigation about structure declaration in C++. (The first is here) But now I came across this post. Specifically I am not sure why this is perfectly fine in C but not in C++.
typedef struct{
int one;
int two;
}myStruct;
struct myStruct; //forward declaration fails
void blah(myStruct* pStruct);
The code above compiles fine on my Ubuntu box with GCC. I reason that it is because the first myStruct lives in the normal namespace where function, variable names live. The second myStruct lives in the Tag namespace. When compiler sees myStruct* in the function prototype, it searches in both namespaces and found myStruct in the normal namspace and that name happen to be a typedef name, so it can be a valid type specifier. The second myStruct can be defined later as whatever the programmer wants to be. There won't be any confusion/collision with the first unnamed myStruct since the programmer has to use struct myStruct to refer to the second one.
But in C++, according to the discussion found in the linked question, my understanding is that the first typedef myStruct lives in the normal namespace as usual. The second myStruct also lives in
the normal namespace(no specific tag namespace in C++?) but can be overshadowed by other identifiers. So my question is why wouldn't the first myStruct which is in the same namespace as the second myStruct shadow the second myStruct?
In a more general sense, other than explicit namespaces introduced by the programmer using the namespace facility provided by the C++ language, are there any pre-defined namespaces disambiguating the use of identifiers (including tags, labels, typedef names, object/functino identifiers) like in C? (C has 4 namespaces pre-defined found in my first investigation). Can I find these in the C++ standard stating where these names belong?
EDIT: It seems I didn't ask the question clear enough. All I want to know is
1) Which namespaces (if there are such defined in the language) do Lables, typedef names, tag names of struct/union/enum, normal function, normal variable/object name belong? (If I missed any other kinds of name, please add.)
2) Why can normal function name, normal variable name shadow tag names, while tag names can NOT.
3) If there is any clauses in C++ that specify the name spaces like in C (Section 6.2.1)
In C++, you cannot use struct myStruct to refer to a tagless structure which has been typedefed. And you cannot define a different struct myStruct, because the name collides with the typedef name.
If you add the tag, then both struct myStruct and myStruct alone will refer to the type, in both C and C++:
typedef struct myStruct {
int one;
int two;
} myStruct;
Here there is no collision in C++ because the name resolves to just one type, and this is specifically allowed by a special rule. C++ Standard section 7.1.3 includes the following rules:
In a given non-class scope, a typedef specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers.
If a typedef specifier is used to redefine in a given scope an entity that can be referenced using an elaborated-type-specifier, the entity can continue to be referenced by an elaborated-type-specifier or as an enumeration or class name in an enumeration or class definition respectively.
In a given scope, a typedef specifier shall not be used to redefine the name of any type declared in that scope to refer to a different type.
Similarly, in a given scope, a class or enumeration shall not be declared with the same name as a typedef-name that is declared in that scope and refers to a type other than the class or enumeration itself.
[ Note: A typedef-name that names a class type, or a cv-qualified version thereof, is also a class-name (9.1). If a typedef-name is used to identify the subject of an elaborated-type-specifier (7.1.6.3), a class definition (Clause 9), a constructor declaration (12.1), or a destructor declaration (12.4), the program is ill-formed.
— end note ]
According to this link
A point from C++0x draft : n3290
Shall this program is correct ?
EX:
namespace X {};
enum Foo
{
X = 0, #1
Y,
Z = X // X refers to the enum, not the type
};
Iam getting error while execution this program like // #1 'X' redeclared as different kind of symbol
But in the above statement link ...namespace scopes containing the enum-specifier. ...etc
please clarify my doubt.
Otherwise Please any one give me an example that proves the above statement(in link) with namespace
There is a difference in that the original question had a struct X instead of namespace X. The namespace name is visible in this scope, and so is Foo::X as enum names "leak" into the surrounding namespace. That creates a conflict.
In C (and therefore also in C++) the name of a struct/class/union is in a separate "tag namespace" (a C term with a different meaning) which allows us to declare another item using the same name in the same scope:
Difference between 'struct' and 'typedef struct' in C++?
The program is illegal. An enum does not introduce a separate scope
(unless you are using C++11 and add class to it), both the
namespace X and the enumeration constant X are in the same scope.
There are only two cases where the same name can be defined more than
once in the same scope: overloaded functions, and one class name. The
special case for the class name is purely for C compatibility, so that
C API's with functions like:
struct stat { ... };
int stat(const char* path, struct stat* buf);
wouldn't break. If both a class name and another name are present, the
other name has precedence, unless preceded by a class keyword.
But of course we shouldn't even think of doing such things, I know, but still this is quite interesting:
class A; //declaration
struct A {...}; //definition
struct B; //declaration
class B {...}; //definition
When I think about it, I don't see any problems if such a thing were really allowed(because struct and class are essentially the same thing). But is it (standard-wise)?
MSVC accepts and compiles it, with a warning.
It is allowed according to the standard, but as some compilers warn about it, it is not very useful.
I believe the warning is/was caused by MSVC using a different name mangling for structs and classes, which would make it even less useful...
On request from #Armen:
7.1.5.3 Elaborated type specifiers, p3
... in any elaborated-type-specifier, the enum keyword shall be used to refer to an enumeration (7.2), the union class-key shall be used to refer to a union (clause 9), and either the class or struct class-key shall be used to refer to a class (clause 9), declared using the class or struct class-key.
As per C++03 Standard 9.1 - 2
"A class definition introduces the class name into the scope where it is defined and hides any class, object, function, or other declaration of that name in an enclosing scope (3.3)."
So it is valid as per the standard.
Playing around a bit with the example code:
#include<iostream>
class A; //declaration
struct A { int i;}; //definition
struct B; //declaration
class B {int j;}; //definition
int main()
{
A obj;
obj.i = 10;
B obj2;
obj2.j = 10;
std::cout<<"sizeof"<<sizeof(struct B);
return 0;
}
Here is the output:
prog.cpp: In function ‘int main()’:
prog.cpp:6: error: ‘int B::j’ is private
prog.cpp:13: error: within this context
The only difference between C++ struct & class is that default access specifier for structure is public while for class it is private.
So, From the above example:
In this case compiler treats A as a structure &
B as a class
As you see, the compiler follows the quote from the standard and the type with the definition is what the compiler recognizes, over the declaration type.
$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.