How is this a definition? - c++

How is this statement a definition? Isn't it supposed to be a declaration only as it does not allocate any memory until we define an object of the type struct date?
struct Date { int d , m , y ; };
I am readng this book called "The C++ programming language" by Bjarne Stroustrup, in which it has been said (in section 4.9) that this a declaration as well as a definition.

It's not a statement in either language. C99 defines statements in 6.8, and C++11 defines statements in 6.
In C, it is not a definition, it's a declaration only: 6.7/5 of C99 says:
A definition of an identifier is a declaration for that identifier that:
—for an object, causes storage to be reserved for that object;
—for a function, includes the function body;
—for an enumeration constant or typedef name, is the (only) declaration of the identifier.
Since this is none of those three things, it's not a definition of an identifier. In the C99 grammar, it's a struct-or-union-specifier (followed by a semi-colon), which in turn is a type-specifier (followed by a semi-colon), which is one of the permitted forms of a declaration (6.7/1).
In C++, it is a class-specifier or class definition: 9/2 of C++11 says
A class-specifier is commonly referred to as a class definition.
In both C and C++ it's common to say that "every definition is a declaration", so that's probably why Stroustrup say's it's a declaration as well as a definition.
In C this is strictly true, because of the definition of "definition" above. In C++ I think it's not actually true in the grammar that a class-specifier is a declaration, but a class definition introduces a complete type, while a class declaration introduces an incomplete type. There's nothing you can do with an incomplete type that you can't also do with the complete type, so the class definition is "as good as" a class declaration like struct Date;, and better.

struct Date; // forward declaration
struct Date{ int d, m, y; }; // class definition (struct is a class-key)
Also see ISO 14882:98 9.1-1 and -2 class-definition
Also relevant ISO 14882:98 3.2 One-definition-rule

This is the declaration of a new type struct Date in C and Date in C++. A declaration is not a statement. And no memory is reserved for the declaration of a new type.

It declares the type Date. It defines the Dates members, and therefore the size of the objects it will create.
It has no methods declared, so doesn't need to define anything else for the class to be complete.
Also, if you don't declare or define a constructor, destructor, assignment operator, etc, C++ will try to automatically synthesise them for you. So this minimal definition of Date includes a default constructor, assignment operator, and destructor.

Related

How is a type that's forward declared in a function parameter list visible outside the function scope? [duplicate]

This question already has an answer here:
Class declaration inside function parameter list
(1 answer)
Closed 1 year ago.
The following program compiles, which I find strange.
void f(class s);
using u = s; // ok, but why?
s is a forward declaration of a class inside a function parameter list, and it seems to me it should not be visible outside the function scope.
basic.scope.param seems the obvious place I would find this rule, but I can't work it out. The wording could be somewhere in dcl.dcl, but I'm not sure where to look.
What rule covers this? Optionally, an explanation of why this rule exists would be nice.
To start with, this rule is not particularly new. It existed since C++'s inception, pretty much. As for C++20, it is written as follows:
[basic.scope.pdecl]
7 The point of declaration of a class first declared in an elaborated-type-specifier is as follows:
...
for an elaborated-type-specifier of the form
class-key identifier
if the elaborated-type-specifier is used in the decl-specifier-seq or parameter-declaration-clause of a function defined in namespace scope, the identifier is declared as a class-name in the namespace that contains the declaration; otherwise, except as a friend declaration, the identifier is declared in the smallest namespace or block scope that contains the declaration.
But you are looking in the latest greatest draft head. You can't find it because the draft has P1787 merged in. It changes the normative wording and moves it with the intent of fixing some outstanding wording issues and improving the standard's approach in a world where modules exist.
Today, the relevant part resides in
[dcl.type.elab]
3 Otherwise, an elaborated-type-specifier E shall not have an attribute-specifier-seq. If E contains an identifier but no nested-name-specifier and (unqualified) lookup for the identifier finds nothing, E shall not be introduced by the enum keyword and declares the identifier as a class-name. The target scope of E is the nearest enclosing namespace or block scope.
And essentially, it means the same thing the C++20 wording does. It introduces the the class name as if by forward declaration into the nearest enclosing scope.
As for why this rule exists. Well... it doesn't exist in C up to date. Which creates some fairly obscure problems for the uninitiated. Consider this simple program:
void func(struct foo*);
struct foo { int bar; };
int main() {
struct foo f;
func(&f);
}
void func(struct foo* pf) {
pf->bar = 0;
}
It produces a slew of diagnostics, which frankly don't seem justified. IMHO it's a shortcoming of C, which in turn is motivation enough for C++ to do things the way it does. Compile the exact same program with a C++ compiler, and it's well formed.
class s is a forward declaration. That is equivalent to
class s;
void f(s);
s is not the name of a variable, but it's a type. So you are just saying that function f takes a parameter of type s.
Also the next line tells that u is equivalent to s. No problem. You don't need the full definition to do that.

Declaration with multiple declarators - Definition?

Is the following declaration also a definition?
int f(), i = 1;
If we would rewrite it like this only the second declaration would be a definition:
int f();
int i = 1;
The c++ standard seems to apply the term definition to entire declarations, but to me it seems like it should be applied to parts of declarations.
Each declarator is individually considered to define or merely declare its identifier.
f() is only declared. There should be a definition somewhere else.
i is defined. A subsequent declaration would need to use extern to avoid being a redefinition.
§3.1 Declarations and definitions in the C++14 standard says,
A declaration is a definition unless it declares a function without specifying the function’s body, it contains the extern specifier or…
The paragraph goes on and on with quite a few rules and exceptions. It may perhaps be a defect in the standard that it fails to mention declarators there, despite discussing features that do not immediately appertain to entire declarations.
We also have §8/3,
Each init-declarator in a declaration is analyzed separately as if it was in a declaration by itself.
This could be interpreted to override the "contagious" formulation of rules in §3.1/2.
Both of them are equivalent statements. In both cases, it is declaration for the function f() and declaration + definition for the variable i.
This declaration
int f(), i = 1;
contains two declarations and one definition. That is it declares a function and it declares and at the same time defines an object.
A function definition is a function declaration that includes its body. However in the declaration above the function does not includes its body. So it is only a declaration of function f with unknown number of parameters if it is a C declaration or without parameters if it is a C++ declaration..
As for variable i then this declaration is at the same time a definition of the variable because a memory is reserved for the corresponding object of type int and moreover the reserved memory is initialized by integer constant 1.
From the C Standard (6.7 Declarations)
5 A declaration specifies the interpretation and attributes of a set
of identifiers. A definition of an identifier is a declaration for
that identifier that:
— for an object, causes storage to be reserved for that object;
— for a function, includes the function body

VS 2013 - IntelliSense reporting false positives?

I'm working on a C++ project where, among other things, I have an interface with a few pure virtual methods. The problem arises when I try to implement that interface - IntelliSense doesn't seem to agree with the derived class's method declaration. An example of such a method:
// DLL_EXPORT -> #define DLL_EXPORT __declspec(dllexport)
// IPlayer
DLL_EXPORT virtual const Grid& GetGrid() const = 0;
Declaration in one of the derived classes:
// Human : IPlayer
DLL_EXPORT const Grid& IPlayer::GetGrid() const;
The error it keeps nagging me with - "IntelliSense: declaration must correspond to a pure virtual member function in the indicated base class". The code compiles without errors and runs fine, all of the "problematic" methods do their jobs as expected during run time. What is worth mentioning is that the error disappears if I remove the IPlayer:: scope qualifier in the derived class. I wanted to keep it there for readability reasons. Also, I am NOT proficient in C++ so there could be something obviously wrong with the example I've provided.
Minimized example:
struct C { virtual void f() = 0; };
struct D : C { void C::f() { } };
This doesn't compile in any version of g++ or clang that I tested. Intellisense in VS2013 uses the EDG frontend, and to quote Jonathan Wakely, "If GCC, Clang and EDG all agree and MSVC disagrees that usually means MSVC is wrong."
To make things more interesting, the relevant paragraphs in the standard actually changed between C++11 and C++14.
In C++11, this is flat-out illegal (N3337 §8.3 [dcl.meaning]/p1):
A declarator-id shall not be qualified except for the definition of a
member function (9.3) or static data member (9.4) outside of its
class, the definition or explicit instantiation of a function or
variable member of a namespace outside of its namespace, or the
definition of an explicit specialization outside of its namespace, or
the declaration of a friend function that is a member of another class
or namespace (11.3).
This sentence was removed in C++14 as a result of CWG issue 482. The proposed resolution for that issue has the following note:
[Drafting note: The omission of “outside of its class” here does not
give permission for redeclaration of class members; that is still
prohibited by 9.2 [class.mem] paragraph 1. The removal of the
enumeration of the kinds of declarations in which a qualified-id can
appear does allow a typedef declaration to use a qualified-id, which
was not permitted before; if that is undesirable, the prohibition can
be reinstated here.]
In C++14, the only applicable rule in §8.3 [dcl.meaning]/p1 is now (quoting N3936):
When the declarator-id is qualified, the declaration shall refer to a
previously declared member of the class or namespace to which the
qualifier refers (or, in the case of a namespace, of an element of the
inline namespace set of that namespace (7.3.1)) or to a specialization
thereof; the member shall not merely have been introduced by a
using-declaration in the scope of the class or namespace nominated by
the nested-name-specifier of the declarator-id.
The relevant part of §9.2 [class.mem]/p1 is:
Except when used to declare friends (11.3) or to introduce the name of
a member of a base class into a derived class (7.3.3),
member-declarations declare members of the class, and each such
member-declaration shall declare at least one member name of the
class. A member shall not be declared twice in the
member-specification, except that a nested class or member class
template can be declared and then later defined, and except that an
enumeration can be introduced with an opaque-enum-declaration and
later redeclared with an enum-specifier.
Since a using-declaration "to introduce a member of a base class into a derived class" is made an explicit exception, it appears that base class members are not considered members for the purposes of the rule that "member-declarations declare members of the class, and each such member-declaration shall declare at least one member name of the class". If so, then it follows that using a qualified-id like void C::f() { } in a member-declaration is also not allowed in C++14, since that qualified-id refers to a member of C, not a member of D.

Typedef-name conflicts with struct tag in C++

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 ]

Statement from ISO standard $3.1 : 1st point from n3242 doc

Statement from ISO standard $3.1 : 1st point
n3242 Says:
A declaration (Clause 7) may
introduce one or more names into a
translation unit or redeclare names
introduced by previous declarations.
If so, the declaration specifies the
interpretation and attributes of these
names. A declaration may also have
effects including:
— a static assertion (Clause 7),
— controlling template instantiation (14.7.2),
— use of attributes (Clause 7), and
— nothing (in the case of an empty-declaration).
ISO 2003 DOC says:
A declaration (clause 7) introduces
names into a translation unit or
redeclares names introduced by
previous declarations. A declaration
specifies the interpretation and
attributes of these names.
can any one explain what is the difference .
They said "A declaration may also have effects including: " ...CAn any one explain what are these effects in terms of Programming
Please explain these effects in Programming way(with an example program)?
I believe it just that some new features have changed the way a declaration works - in the small details.
For example, this does't just introduce some names, but also affects compilation of the code.
struct A
{
int x;
};
struct B
{
A a;
static_assert(sizeof(a) > 10, "Wrong member size");
};
We also have the empty declaration (which I belive can only be used inside a class):
struct C
{
void f()
{ }; // Semicolon here is allowed, but is an empty declaration
};
The empty declaration is a declaration that does not introduce a name (because it is empty).
Figured out the "affects template instantiation" as well, I think:
template<class T>
class X
{
// some members
};
extern template class X<int>;
extern template class X<char>;
Tells the compiler that X<int> and X<char> will be instantiated somewhere else and does not have to be generated here.