Is there a more succinct way to define a class in a namespace than this:
namespace ns { class A {}; }
I was hoping something like class ns::A {}; would work, but alas not.
You're close, you can forward declare the class in the namespace and then define it outside if you want:
namespace ns {
class A; // just tell the compiler to expect a class def
}
class ns::A {
// define here
};
What you cannot do is define the class in the namespace without members and then define the class again outside of the namespace. That violates the One Definition Rule (or somesuch nonsense).
You can do that, but it's not really more succint.
namespace ns {
class A;
}
class ns::A {
};
Or
namespace ns {
class B;
}
using ns::B;
class B {
};
The section you should be reading is this:
7.3.1.2 Namespace member definitions
3 Every name first declared in a namespace is a member of that namespace.[...]
Note the term -- declaration so D.Shawley (and his example) is correct.
No you can't. To quote the C++ standard, section 3.3.5:
A name declared outside all named or
unnamed namespaces (7.3), blocks
(6.3), fun (8.3.5), function
definitions (8.4) and classes (clause
9) has global namespace scope
So the declaration must be inside a namespace block - the definition can of course be outside it.
Related
Inside a function one can employ the using declaration to import a name in the current scope, like
namespace A {
int y;
}
void f() { using A::y; }
A using declaration can be used in a class definition, to alter the accessibility of an inherited member, but also it is useful to explicitly bring a member inherited from a template class
template <bool activate>
struct A {
int x;
};
template <bool activate>
struct B : public A<activate> {
using A<activate>::x;
};
This is particularly useful, as it avoids the need to access to x via this->x or A<activate>::x. This can be used only inside the body of the definition, but not inside a member function.
template <bool activate>
struct A {
int x;
};
template <bool activate>
struct B : public A<activate> {
int f() const noexcept {
// This gives: "error: using-declaration for member at non-class scope"
// using A<activate>::x;
return x;
}
};
Is there a rationale for this restriction of the language, that is, for the fact that using A<activate>::x can only be placed inside the definition of the class?
Absent a direct statement on the subject in Design & Evolution of C++, it’s hard to reliably infer intent for something like this. That said, until recently, the standard described using-declarations as introducing declarations as synonyms for the named declarations. In that view, it would be more than a little strange to have a member declaration belong to a block scope. Now they are considered to be redirects that are replaced by their referents during name lookup, which would be more consistent with this notional usage.
I just read this answer, and it completely puzzles me.
I was always thinking a class declaration can appear many times, and only the definition has to exist only once, like:
/*class Class {*/
class A; // (1) forward declaration
class A { // (2) definition, only once
int m;
};
class A; // (3) declaration again, legal?
class A a; // (4) declaration again, legal?
/*};*/
From the linked answer: (3) (and (4)?) is illegal if the code above is nested inside a class (definition and declarations of class A are nested inside class Class).
On cppreference, I found an example of the above, not nested:
struct s { int a; };
struct s; // does nothing (s already defined in this scope)
void g() {
struct s; // forward declaration of a new, local struct "s"
// this hides global struct s until the end of this block
s* p; // pointer to local struct s
struct s { char* p; }; // definitions of the local struct s
}
See the second line.
Question: Given that it is illegal inside a class, is my example code, and the cppreference example above, legal when not nested inside a class? Or more generally: When can a class declaration follow a definition (how is it inside namespaces for example)? If it is legal, why is there a difference?
From [basic.def]:
A declaration (Clause 7) may introduce one or more names into a translation unit or redeclare names introduced by previous declarations.
From [class.name]:
A declaration consisting solely of class-key identifier; is either a redeclaration of the name in the current scope or a forward declaration of the identifier as a class name. It introduces the class name
into the current scope.
So it's generally legal to do this. There's just the one exception in [class.mem]:
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.
Perfectly OK in namespace scope, not allowed in class scope.
As to why? Well, this rule let's you "forward" declare all the classes you need everywhere you would typically be allowed to do so:
// a.h
struct C;
struct A {
C* c;
};
// b.h
struct C;
struct B {
C& c;
};
without having to worry about somebody actually including the full declaration and breaking everything for you:
// d.h
#include "c.h"
#include "a.h" // now C was already declared!
#include "b.h" // and here too!
struct D { ... };
This isn't so much of a concern within a class definition. It can't exactly span multiple files. So the inability to redeclare nested types doesn't actually achieve anything.
class A; This is a forward declaration of incomplete class A (legal).
class A { int m; }; This is the definition of Class A (legal).
class A; This is re-declaration of class A (legal).
class A a; This is declaration of object a of type A (legal).
I've two question about this code bellow:
namespace A { class window; }
void f(A::window);
namespace A
{
class window
{
private:
int a;
friend void ::f(window);
};
}
void f(A::window rhs)
{
std::cout << rhs.a << std::endl;
}
1) why do I need to qualify the member function f inside window class to be global by doing ::f(window) ?
2) why do I need to predeclare the function f(A::window) in this particular case, whereas when the class is not defined inside a namespace it's ok for the function to be declared after the function is declared a friend.
When you declare f() as a friend it's actually done in the enclosing namespace of the containing class (A in this case) if a forward declaration is not already present.
So this...
namespace A
{
class window
{
private:
friend void ::f(window);
};
}
essentially becomes this...
namespace A
{
class window;
void f(window);
class window
{
private:
friend void f(window);
};
}
Edit: Here is a snippet from the C++ standard that explicltly talks about this scenario:
Standard 7.3.1.2 / 3 :
Every name first declared in a namespace is a member of that namespace. If a friend declaration in a nonlocal class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship).
As for 1), your function is not in the namespace, so you must use :: to tell the compiler to search it outside the namespace.
Otherwise, it will only look for function inside the namespace (that's why they exist). Koenig lookup doesn't apply here, as window class is inside the namespace.
not too sure about 2) though, but i bet it is related to 1).
1) because function f is declared and defined outside of the current namespace. If you moved the definition of your class into the same namespace as the function whether global or otherwise you wouldn't need to.
2) you always need to declare a function before it is referenced. Your class references the function with the friend statement.
the following code will help me illustate my question to you directly:
#include<iostream>
class foo {
public:
class bar {
public:
bar(int a) : m_a(a) {}
void say() { std::cout << m_a << std::endl;}
private:
int m_a;
};
};
int main()
{
foo::bar b(3);
b.say();
}
as you see, to declare a object of class bar, we use the quite namespace like syntax "foo::bar", although actually bar is just an embebed class type in class foo. my question
is does the scope of a class itself is a namespace in c++?
No, a class is not a namespace. A class does form a declarative region, though.
You use the same syntax (the :: operator) to refer to names declared at class scope as you do to refer to names declared at namespace scope.
The class is not a namespace, it is a scope. You already used this term yourself. Namespace is a scope. Class is a scope as well. The :: operator is a scope resolution operator. Scope, not namespace, is the fundamental term that can act as a "common denominator" in this case. Scope is the reason why you can use the :: operator with both classes and namespaces on the left-hand side.
Another interesting distinction between classes and namespaces is that a namespace can be declared over multiple files and in multiple parts, but a class cannot. For example, you could do:
File a.hpp:
namespace Foo {
int memberA;
}
File b.hpp:
namespace Foo {
int memberB;
}
...
namespace Foo {
int memberC;
}
The scope of a class is not the same as the scope of a namespace. Classes can be templated, which affects the definitions in its scope. Classes can also have definitions that are only able to be used within that scope (private and protected).
The class name itself is not a namespace, although the scoping operator treats it as such, or almost as such anyways.
In a previous Q&A (How do I define friends in global namespace within another C++ namespace?), the solution was given for making a friend function definition within a namespace that refers to a function in the global namespace.
I have the same question for classes.
class CBaseSD;
namespace cb {
class CBase
{
friend class ::CBaseSD; // <-- this does not work!?
private:
int m_type;
public:
CBase(int t) : m_type(t) {};
};
}; // namespace cb
class CBaseSD
{
private:
cb::CBase* m_base;
public:
CBaseSD(cb::CBase* base) : m_base(base) {};
int* getTypePtr()
{ return &(m_base->m_type); };
};
If I put CBaseSD into a namespace, it works; e.g.,
friend class SD::CBaseSD;
but I have not found an incantation that works for the global namespace.
I am compiling with g++ 4.1.2.
As stated in some of the comments below the question, the code in the question appears to work with me (Linux-Ubuntu-16.04, gcc version 5.4.0), provided that the friend class was forward-declared.
In pursuit of an answer, I came across this post that both explains proper technique for making friend class of a global namespace and answers why it needs to be declared the way it does. It is a nice thread because it references the standard.
As stated earlier, the class of a global namespace must be forward declared before it can be used as a friend class to a class within a namespace.
add the forward declaration like below
namespace {
// anonymous namespace declaration
class CBaseSD;
}
then your normal
friend class CBaseSD;// no need of ::
works in CBase