According to N4567, 3.3.7 paragraph 4 says,
The potential scope of a declaration that extends to or past the end of a class definition also extends to the regions defined by its member definitions, even if the members are defined lexically outside the class...
However, I don't see a need for making it clear because such a member definition must be in the scope of that declaration regardless of its lexical positioning. In other words, it seems there is no case where such a member definition dwells outside the scope of the declaration. See the following example:
int always_visible=10;
class some {
int foo(void);
};
int some::foo(void) {
// no ambiguity occurs because its member definition
// is always in the scope of always_visible.
return always_visible;
}
I don't think it's possible for its member definition to precede the declaration of always_visible, in which case the wording above might be useful. Then, why is that clarification needed?
Related
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
The following code produces a compile error (on a recent version of gcc at least):
namespace a {
class X { friend void ::foo(); };
}
The error is:
'void foo()' should have been declared inside '::'
If we remove :: from the declaration, according to the standard, foo will be introduced into the namespace a (although it won't be visible). Predeclaring foo inside of a is not required.
My question is, given the above, why is predeclaring within the global namespace a requirement? Why doesn't the name foo become a member of the global namespace? I couldn't find any paragraph in the standard that would explicitly forbid that either, so I'm curious to know.
The paragraph you're looking for is [dcl.meaning] (8.3 (1) in C++11):
(...) A declarator-id shall not be qualified except for the definition of a member function or static data member outside of its class, the definition or explicit instantiation of a function or variable 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. 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).
(emphasis mine) What this means is that you cannot write
namespace a { }
void a::foo() { }
unless a::foo is already declared with an unqualified declarator inside the namespace. And since there is no exception for friends, you cannot do this for friends either.
A footnote in [namespace.memdef] (7.3.1.2 (3) in C++11) mentions this even more explicitly for the special case of friends:
(...) If a friend declaration in a non-local class first declares a class or function95 the friend class or function is a member of the innermost enclosing namespace. (...)
95) This implies that the name of the class or function is unqualified.
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.
I'm working on a source editor for C++ and came up with simple optimization that I do not need to invalidate (e.g. highlighting, rebuild AST, do static analysis) the code before the currently edited statement (basically, before the previous semicolon/closing brace) but I am not sure if this is always true for C++.
E.g. in Java it is possible to call functions declared/defined after the edit location. Hence, if the user adds an argument to the function then error marker should be placed in the code before the edit location. In C++ function should be declared before it is used (and if the declaration does not match definition the error will be on definition).
Member function bodies defined inline in the class will be conceptually (and actually, in the compilers I know) parsed at the end of the class and can thus access members of the class declared after them.
Templates are compiled in two phases. The first phase is where they're defined, the second where they're instantiated. The current compilers can blame you for template errors at the point of instantiation, when substituting the actual arguments leads to an error in the template.
It would be entirely reasonable for your editor to follow the same logic. If the template definition looks good when you see it, it passes the first phase. When the code being edited instantiates a template, re-check, and blame any errors in the second phase on the instantiation.
This hints at a more fundamental problem. Where do you say an error occurred? The C++ standard doesn't care. As far as it's concerned, "syntax error somewhere" is a sufficient diagnostic. So, if there's an inline method trying to access a non-existing member this->a, you can claim there's an error in the method. But with equal validity, you can claim at the final }; that the class failed to define the necessary member a.
The underlying cause of all these errors is that two pieces of code must agree on something. When they don't, you can choose who to blame. For your editor, you could blame the fragment which came last. It's just a matter of getting the diagnostic wording right.
In general, outside a template definition, the rules for name lookup in C++ require a name to be declared before the point at which it is used. Your idea would therefore work in most cases. Unfortunately - as pointed out by SebastianRedl - there is a special case in which this rule of thumb does not apply.
Within a class definition, the declarations of all members of the class (and its enclosing class(es)) are visible during name lookup within the body of a member function (including a ctor-initializer-list or exception-specification), or in a default argument of a member function.
An illustration:
struct A
{
struct B
{
static void f(int i = M()) // uses 'A::M' declared later
{
A::f(); // calls A::f(int) declared later
}
};
static void f(void*)
{
f(); // calls A::f(int) declared later
}
static void f(int i = M()) // uses 'M' declared later
{
}
typedef int M;
};
If the token that was modified occurs within a member function-body or a default argument, you would have to reparse all classes that enclose the token.
From C++ Working Draft Standard N3337:
3.4.1 Unqualified name lookup [basic.lookup.unqual]
A name used in the definition of a member function (9.3) of class X following the function’s declarator-id
or in the brace-or-equal-initializer of a non-static data member (9.2) of class X shall be declared in one of
the following ways:
— before its use in the block in which it is used or in an enclosing block (6.3), or
— shall be a member of class X or be a member of a base class of X (10.2), or
— if X is a nested class of class Y (9.7), shall be a member of Y, or shall be a member of a base class of Y
(this lookup applies in turn to Y’s enclosing classes, starting with the innermost enclosing class), or
— if X is a local class (9.8) or is a nested class of a local class, before the definition of class X in a block
enclosing the definition of class X, or
— if X is a member of namespace N, or is a nested class of a class that is a member of N, or is a local class
or a nested class within a local class of a function that is a member of N, before the use of the name,
in namespace N or in one of N ’s enclosing namespaces.
I am new to C++.
I have a class like this:
class CodeTest
{
private:
static const int TOTAL=100;
};
Is TOTAL a declaration or a definition?
When I was reading Scott Meyer's book, it was mentioned that in the implementation file we need to define something like:
const int CodeTest::TOTAL;
Why is this required?
The declaration in an implementation file outside of the header is required because otherwise every translation unit that includes this header would define its own object (that is, its own storage for the variable).
This would violate the One Definition Rule. A consequence would be e.g. that if the variable was changed in one translation unit, this change would be invisible to other translation units. Now, this isn’t that relevant since the variable is constant. However, taking its address would also yield different pointers in different translation units.
Since this stirred up some controversy, I looked in the standard, and #Nawaz is right, I was wrong.
9.4.2/2
If a static data member is of const integral type [...]. The member
shall still be defined in a namespace scope if it is used in the
program and the namespace scope definition shall not contain an
initializer.
So what you have there is a declaration, and the variable is initialized to a value. Outside the class you must define the variable, but not assign a value to it.
The part with const integral type only applies to this particular case - i.e. you can initialize said type inside the class, but all static data members must be defined outside.
To answer the question:
Regardless of whether the definition is or isn't required outside the class (depending on whether you use the member or not), whatever is inside the class (initialized or not) is just a declaration.
First part of the question:
This line: static const int TOTAL=100; is a declaration followed by an initialisation.
TOTAL is an identifier.
Second part of the question
const int CodeTest::TOTAL is required to initialize the variable.
static const int TOTAL=100; // is a declaration followed by an initialisation.
From the C++ standard section 3.1:
A declaration introduces names into a translation unit or redeclares names introduced by previous declarations. A declaration specifies the interpretation and attributes of these names.
The next paragraph states that a declaration is a definition unless...... it declares a static member within a class definition:
struct X
{
int a; // defines a
static int b; // declares b
};
You can read more about definition and declaration here: SO: What is the difference between a definition and a declaration?