Member's potential scope for struct vs namespace - c++

Referring to this code:
namespace Y {
char f() { return y; } // error: y was not declared in this scope
char y;
}
struct X {
char f() { return x; } // OK
char x;
};
As per basic.scope.namespace#1:
The declarative region of a namespace-definition is its
namespace-body. Entities declared in a namespace-body are said to be
members of the namespace, and names introduced by these declarations
into the declarative region of the namespace are said to be member
names of the namespace. Its potential scope includes its namespace from the name's point of declaration onwards.
QUESTIONS
Is it correct to say that the error was due to the fact that Y::y is not yet declared in Y::f()?
I can't figure why there isn't a "reodering" for namespace members during declaration while for struct there is. What could be the reason for disallowing such behavior? Does the standard says something similar?

Is it correct to say that the error was due to the fact that Y::y is not yet declared in Y::f()?
Yes.
I can't figure why there isn't a "reodering" for namespace members during declaration while for struct there is. What could be the reason for disallowing such behavior? Does the standard says something similar?
The biggest hindrance for namespaces as opposed to classes, is that they are never "closed". You can always add members to a namespace by re-opening it in another translation unit and declaring more stuff in it. A class declaration however, for all its members, must appear entirely in a single translation unit. And there is no adding to it later.
[class.mem]/1
The member-specification in a class definition declares the full set
of members of the class; no member can be added elsewhere.
The problem for namespaces is intractable. But classes only require a little more, quite localized, work.
It is therefore much easier, both to a language designer and a compiler writer, to demand namespace declarations appear before they are used.
You should also note that you can only use other members of the class in only a specific set of places inside the definition.
[class.mem]/6
A class is considered a completely-defined object type ([basic.types])
(or complete type) at the closing } of the class-specifier. Within the
class member-specification, the class is regarded as complete within
function bodies, default arguments, noexcept-specifiers, and default
member initializers (including such things in nested classes).
Otherwise it is regarded as incomplete within its own class
member-specification.

You are mistaken thinking that for structures there is "reordering".
Consider the following structure definition.
#include <iostream>
struct A
{
char s[N];
enum { N = 10 };
};
int main()
{
return 0;
}
The compiler will issue an error because the name N is not yet declared when it is used in the array declaration. So neither "reordering" exists in the class scope. As for member functions then names used within a member function are at first searched in the class scope.
Moreover a name declared in a namespace can hide the same name declared in the outer namespace. As result the "reordering" breaks scopes of variables.

Related

Class member function defined outside its namespace

The following code compiles perfectly with the latest MSVC, GCC and CLang available at godbolt online compiler explorer site. I wonder why:
namespace ns
{
struct Test
{
void foo();
};
}
using namespace ns;
// Alert! Member function defined outside its namespace!
void Test::foo()
{
}
int main()
{
ns::Test obj;
obj.foo();
return 0;
}
cppreference claims that if a member function is defined outside its class, then it must be defined at the namespace of that class. See the very top of the cppreference page about member functions.
But still, the compilers accept the code. It's really unlikely that all three independent compilers have the same bug, right? So, is there a good reason behind them accepting such code?
12.2.1 Member functions [class.mfct]
A member function may be defined (11.4) in its class definition, in which case it is an inline member function (10.1.6), or it may be defined outside of its class definition if it has already been declared but not defined in its class definition. A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition.
This does not mean the definition must appear in the immediately surrounding scope. It can appear in any enclosing namespace, even if that is several layers up.
However, this would be illegal:
namespace a {
struct X {
void Y();
};
}
namespace b { // not an enclosing namespace
void X::Y()
{
std::cout << "Do a thing!\n";
}
}
Quoting C++17 (n4659) 12.2.1 [class.mfct]/1:
A member function definition that appears outside of the class definition
shall appear in a namespace scope enclosing the class definition.
This means it must be defined in the namespace which contains the class, or any parent namespace of that namespace. In your case, it's defined in the global namespace, which does indeed enclose (indirectly) the class definition.
using namespace ns;
5) using-directive: From the point of view of unqualified name lookup of any name after a using-directive and until the end of the scope in which it appears, every name from ns_name is visible as if it were declared in the nearest enclosing namespace which contains both the using-directive and ns_name.
It means that in the current scope ns can be omitted from addressing something inside that namespace.
As such when you write this code:
using namespace std;
vector<string> vectorofstrings;
You don't have to write
std::vector<std::string> vectorofstrings;
The namespace of a class is the name of the class. So if you have:
namespace aNamespace{
class aClass{
int aMember;
void aFunction();
};
}
Then the fully qualified lookup is ::aNamespace::aClass and a function must be defined as being part of void ::aNamespace::aClass::aFunction(){}

C++ standard default namespace

I am unsure if the two data member declarations in class B are equivalent.
//file0.h
namespace C
{
typedef int Id;
}
//file1.h
namespace A
{
typedef int Id;
}
//file2.h
namespace A
{
class B
{
public:
// ...
//Want to add data member theId as:
//Id theId;
//or
//A::Id theId;
}
}
That is, in the absence of A::, is there a default namespace the C++ standard uses in cases like this one? e.g., it may default to namespace A because the class is being declared in it.
If one uses Id theId, which namespace would it use, A or C?
Edit 1: Commented out code to avoid confusion.
Edit 2: Added another "theId" with a different namespace to illustrate better the question.
Answer is Id results in A::Id theId.
Why?
Id (without the A::) is an unqualified name. C++ then resorts to this rule to find the right Id:
Member function definition For a name used inside a member function
body, a default argument of a member function, exception specification
of a member function, default member initializer, or inside a nested
class definition (including names of the bases from which the nested
class is derived), the scopes searched are the same as in class
definition,[...]
[Class definition] the following scopes are searched:
d) if this class
is a member of a namespace, or is nested in a class that is a member
of a namespace, or is a local class in a function that is a member of
a namespace, the scope of the namespace is searched until the
definition of the class, enclosing class, or function. if the lookup
of for a name introduced by a friend declaration: in this case only
the innermost enclosing namespace is considered, otherwise lookup
continues to enclosing namespaces until the global scope as usual.
Reference: http://en.cppreference.com/w/cpp/language/unqualified_lookup

The meaning of the name used in the scope word combinantion

I don't understand sense of the name used in.... What does it mean? For example (3.4.1/7):
A name used in the definition of a class X outside of a member
function body...
Consider the following example:
class A { static const int a = 4; }
int b = A::a;
The name a after the nested-name-specifier used into the global scope or it used into the class scope?
The namespace analog is defined pretty clear in the 7.3.1/6:
The enclosing namespaces of a declaration are those namespaces in
which the declaration lexically appears, except for a redeclaration of
a namespace member outside its original namespace (e.g., a definition
as specified in 7.3.1.2).
Disclaimer: Warning, language-laywer answer.
What is a "scope"?
Generally, I'd say that a scope is understood as the part of the program text enclosed by {} other than the initializer-brackets. TC++PLv4 p157 "A declaration introduces a name into a scope".
Declarative region
In [basic.scope.declarative]/1, we find the definition of a declarative region:
Every name is introduced in some portion of program text called a declarative region, which is the largest part of the program in which that name is valid, that is, in which that name may be used as an unqualified name to refer to the same entity.
I think we can see the part after "that is" as a definition of the validity of a name.
Scope
[basic.scope.declarative]/1 continues with the definition of scope:
In general, each particular name is valid only within some possibly discontiguous
portion of program text called its scope.
This only defines what the scope of a name is. In the phrases "used in global scope" or "used in the scope of the class", the term scope is used not related to a specific name. Similarly, [basic.scope.declarative]/3
The names declared by a declaration are introduced into the scope in which the declaration occurs, except [...].
Here, the term scope is also used in that second meaning, unrelated to a specific name.
Defining the second meaning of "scope"
Several language features such as block statements, namespaces and classes introduce a new scope. E.g. [stmt.block]/1
A compound statement defines a block scope.
Scope in its second meaning is used at least in three different contexts:
looked up in the scope of X
used in the scope of X
is in the scope of X
Looked up in the scope of X
Example: 3.4.3/1
If the nested-name-specifier of a qualified-id nominates a class, the name specified after the nested-name-specifier is looked up in the scope of the class, except for the cases listed below.
class X
{
int m;
void foo() { int n; }
};
decltype(X::m) v; // legal
decltype(X::n) w; // illegal
In this context, the scope of class X does not extend to any nested scopes such as member functions or nested classes.
Used in the scope of X
Example: 3.3.7/2
The name of a class member shall only be used as follows:
in the scope of its class (as described above) or a class derived from its class,
[...]
class X
{
int m;
void foo()
{
decltype(m) n;
}
static int o;
};
int X::o = decltype(m)();
Here, the scope of class X extends to nested scopes and other parts of the program, such as definitions of members outside of the class body.
Note that the initializers of static data members, nested classes and local classes are explicitly defined to be in the scope of wherever the static data member / class has been declared. For member functions, I can only find non-normative notes such as 9.3/5
The member function f of class X is defined in global scope; the notation X::f specifies that the function f is a member of class X and in the scope of class X.
As I understand it, this "is in the scope of" for member functions and nested/local classes says that those newly introduced scopes are nested scopes.
"Used in the scope of X" does not occur very often in the Standard. One could argue that 3.3.7/2 should be extended to nested scopes, to make "used in the scope of" consistent with "looked up in the scope of".
To be in the scope of X
Example: 8.5/13
An initializer for a static member is in the scope of the member's class.
class X
{
static int m;
static int n;
};
int n;
int o;
int X::m = n; // X::n
int X::n = o; // ::o
Name lookup for unqualified names searches the scopes (plural) "in the order listed in each of the respective categories" [basic.lookup.unqual]/1. For the initializers of the two static data members, the scope of class X is searched first, then any base classes, then the enclosing scope (here: the global scope), [basic.lookup.unqual]/7.
What is meant with "to be in the scope of X" seems to me that for unqualified lookup, the scopes searched are the ones that are searched for names used inside X, maybe plus access rules (initializers of static data members may access private members etc). As said above, this effectively nests scope of member functions and nested classes defined outside their enclosing class' body in the scope of that enclosing class.
Trying to define the scope of X
Not including the weird extensions of "used in the scope of X".
3.3.3 to 3.3.9 categorize various kinds of scopes of names. We can use these categories to categorize the parts of our program where names can be declared: A part of a program where names with block scope can be declared is a block scope. A part of the program where names with class scope can be declared is a class scope. We still need to differentiate different scopes of the same kind:
void foo()
{ // begin scope A
int a; //
{ // begin scope B
int b; //
int c; //
} // end scope B
int d; //
} // end scope A
The Standard calls A an outer scope of B (in name lookup). However, the scope B is not part of the scope A. Maybe something like "B is in the scope of A, but the names declared inside B are not in the scope of A". Consider:
class A
{
int m;
class B
{
int n;
};
};
Here, name lookup "in the scope of the class A" won't find members of the nested class B with unqualified lookup. Also relevant: anonymous unions.
I think the best way to perform this separation is to look at the individual language features which can introduce a scope. For example, [stmt.block]/1 "A compound statement defines a block scope." We can then look at any part X of the program, find the closest previous language feature that introduced a scope which has not ended yet(*), take all the regions of the program where newly declared names are in the same scope (**), and call this the enclosing scope of X.
(*) not ended yet: for a block, the end of the block etc. (i.e., as specified by the language feature) Alternatively, not ended yet = where a name could have been declared that is still valid
(**) in the same scope: searching, beginning from this new declaration, the closest previous language feature that introduced a scope which has not ended yet, shall find the same part of the program
This seems to comply with what has been intended as the definition of declarative region as used in [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 [... = be function overloads], or [... = various exceptions].
This, as far as I can see, contradicts the definition given in [basic.scope.declarative]/1:
int main()
{
int x;
{
int x;
}
}
Here, we have two declarations specifying the same unqualified name. The outer x as a name is valid also inside the inner {}; yet, this is a perfectly legal C++ program. I suspect that declarative region in fact shouldn't be associated with a single name.
I think it is possible to simplify this definition of scope by using the terminals { and }.
This phrase
A name used in the definition of a class X outside of a member
function body...
considers all names that are used in the definition of a class that is starting from the class head and ending in the closing brace excluding names used in member functions (names used in member functions are considered in other paragraph).
For example
class B : public A
{
int x;
int a[i];
C z;
//..
};
So these names are A, x, a, i, C, z.
Take into account that though names x, a, and z are defined in the class their names can be used in other member definitions of the class.
As for your code example
class A { static const int a = 4; }
int b = A::a;
The name a after the nested-name-specifier used into the global scope or it used into the class scope?
then name a is searched in the class scope of class A but its qualified name used in the global scope to initialize variable b.
Consider another example though it has nothing common with the phrase you cited but has a relation with your code.
struct A
{
static int a;
static int b;
};
int A::a = 10;
int A::b = a;
Here is used name a without nested name specifier. It is one more rule how names are searched in the class scope.

Why do non-const, non-int/enum static data members have to be initialized outside the definition?

I understand that only data members which are static, const and int/enum (pre c++11) can be initialized inside the class declaration. "All other static data members must be defined at global namespace scope (i.e. outside the body of the class definition) and can be only initialized in those definitions".
Why can't other static data members be initialized in the class definition? Was there a specific reason this was forbidden?
If the data members are specific to the class, why are they declared at the global namespace scope and not some scope relevant to their class?
Why can't other static data members be initialized in the class definition? Was there a specific reason this was forbidden?
Most likely because C++ has separate translation units. The compiler needs to pick an object file where the initialization logic for those symbols will be placed. Forcing this to be in a specific source file makes that decision easy for the compiler.
If the data members are specific to the class, why are they declared at the global namespace scope and not some scope relevant to their class?
Because that's just how C++ does class members. This is no different than other class members like member functions:
Header file:
namespace example {
// Class declared in header
struct some_class
{
// Member variable
static float example;
// Member function
void DoStuff() const;
};
}
Source file:
namespace example {
// Implement member variable
float some_class::example = 3.14159;
// Implement member function
void some_class::DoStuff() const
{
//....
}
}
There's a specific exception to allow static const integral members to be initialized in the header because it allows the compiler to treat them as compile-time constants. That is, you can use them to define sizes of arrays or other similar bits in the class definition.
Why can't other static data members be initialized in the class definition? Was there a specific reason this was forbidden?
In general, all static objects require a definition, in one single translation unit, so that they have a well-defined address. As a special exception, static, constant, non-volatile class members don't need a definition if their address is not required, and they have a simple enough type that their value can be replaced by a compile-time constant.
Historically, "simple enough" was defined as an integral or enumeration type; C++11 extends that to include any literal type with a constexpr specifier.
If the data members are specific to the class, why are they declared at the global namespace scope and not some scope relevant to their class?
They are not declared at the global namespace scope. They are declared and scoped within the class.
If you mean, why are they defined outside the class definition, that's because there must be only one definition of the static member in the whole program; but the class must be defined in each translation unit that uses it.
Why can't other static data members be initialized in the class
definition? Was there a specific reason this was forbidden?
A static data member is in many respects (and especially from the point of view of a compiler) similar to a namespace-scope data object with external linkage.
The declaration of a static data member is just a declaration, not a definition. It is similar to an extern declaration of a global object and must be included into any translation unit where the object may be used.
The definition must appear in exactly one translation unit and this is where the initializer expression belongs. Unless an expression fulfills the strict criteria of a constant expression, its value may well depend upon the time and context it is called. Having such an initializer expression occur in multiple translation units would make the execution context and time of the initialization and finally the initial value ambiguous.
A class-scoped compile-time constant was deemed sufficiently valuable to make an exception for certain kinds of constant static members (which then could be used to initialize enums or specify array dimensions, etc). With constant expressions it is at least more difficult to accidentally incur different initializer values in different translation units. This concept was extended in C++11 with constexpr members.
If the data members are specific to the class, why are they declared
at the global namespace scope and not some scope relevant to their
class?
The declaration is within the class scope. The non-definition declaration is literally within the class definition and the definition appears at namespace scope, just like any other out-of-class definition of a class member. The member name is qualified by the class name, so it is clearly denoted as a member of the class and the initializer expression is actually considered to be within the scope of the class (at least in C++11; I have no C++98/03 standard available here).
You have to look at it the other way around. Basically, static data members must be defined and initialized outside the class definition, in a source file. There's an exception for static const int because it avoids various ugly workarounds for defining the size of a member array.
They would be re-initialized every time the class was instantiated. Every time you create a new object of type Foo, the static variables for all Foos would be reset to their initial value, which is probably not what you want. Therefore, if you want to use static variables with your object, they either a) can't change their value, meaning that reinitializing them to the same value is safe, or b) can only be changed outside the context of an initializer function.

namespaces, classes and free functions - when do you need fully qualified names

In my example below, why do I have to fully qualify the name of the free function in the cpp to avoid linker errors and why does it work for the class function without? Can you explain the difference?
ctest.h:
namespace Test
{
int FreeFunction();
class CTest
{
public:
CTest();
~CTest();
};
}
ctest.cpp:
#include "ctest.h"
using namespace Test;
// int FreeFunction() -> undefined reference error
int Test::FreeFunction() -> works just fine
{
return 0;
}
CTest::CTest() -> no need to fully qualify name, i.e. Test::CTest
{}
CTest::~CTest()
{}
Thanks for your time & help.
int FreeFunction(void);
is just a declaration whereas the below is a definition.
class CTest
{
public:
CTest();
~CTest();
};
If you want to provide definition for an already declared entity in a namespace (e.g. in an enclosing namespace), it has to be fully qualified name.
EDIT2:
Here is something that would give you some more clarity. Note no using directive in this code.
namespace Test {
int FreeFunction(void); // declare
class CTest; // declare
}
int Test::FreeFunction(){return 0;} // define
class Test::CTest{ // define
};
int main(){}
EDIT 3: Declaration vs Definition (C++0x)
$3.1/2-
A declaration is a definition unless
it declares a function without
specifying the function’s body
(8.4), it contains the extern
specifier (7.1.1) or a
linkage-specification25 (7.5) and
neither an initializer nor a
function-body, it declares a static
data member in a class definition
(9.4), it is a class name
declaration (9.1), it is an
opaque-enum-declaration (7.2), or it
is a typedef declaration (7.1.3), a
using-declaration (7.3.3), a
static_assert-declaration (Clause 7),
an attribute-declaration (Clause 7),
an empty-declaration (Clause 7), or a
using-directive (7.3.4).
While FreeFunction will resolve to Test::FreeFunction if you refer to it or call it after providing the using namespace Test; line, as far as defining the function goes, the compiler has no way to know if you're defining an entirely new function FreeFunction outside of any namespace, or whether you're defining the already declared Test::FreeFunction. The compiler defaults to thinking that you're defining an entirely new function.
For CTest::CTest, however, you're already referring to the class Test::CTest, and since there's no class or namespace CTest outside of the Test namespace, well, the reference to CTest::anything is unambiguous. So it knows that the constructor and destructor definitions refer to the in-namespace class CTest.
I think it's a small price to pay, to have to write Test::FreeFunction.
Hope this helps!
If you don't qualify FreeFunction definition, the compiler does not know for sure anther you want to provide implementation for the previously forward-declared Test::FreeFunction or for a separate FreeFunction in the current namespace.
On the other hand, there's only one way to resolve the name CTest - as the class definition from the Test namespace. Thus, there's no need to fully qualify it.
However, if the CTest name resolution is ambiguous (say there's another CTest class in the current namespace as well), you will have to fully qualify the method declarations.
When implementing a function it is usually preferable, I find, to open the namespace. Remember you can re-open them...
// in Test.cpp
namespace Test
{
int FreeFunction()
{
return 0;
}
}