I sometimes declare classes in nested namespaces and when it comes to defining their member functions, I prefer not to have to qualify each one with these nested namespace names, especially if they are long-ish.
Adding "using namespace " (or, for more precise targetting, "using ::SomeClass") before I define the member functions seems to obviate the need to qualify each definition, but I can't find anywhere in the spec that guarantees this, and I'm worried that it might be a behaviour that only works with GCC. I note that there doesn't appear to be a similar mechanism for skipping the need to add the qualifiers when defining free functions(?).
As an example of what I mean:
Header:
// example.h
namespace SomeNamespace
{
class SomeClass
{
public:
void someMemberFunction();
};
void someFreeFunction();
};
Implementation:
// example.cpp
#include "example.h"
using namespace SomeNamespace;
void SomeClass::someMemberFunction()
{
// OK: seems to define SomeNamespace::SomeClass::someMemberFunction(),
// even though we didn't qualify it with SomeNamespace::
}
void someFreeFunction()
{
// Not what we wanted; declares and defines ::someFreeFunction(), not
// SomeNamespace::someFreeFunction() (quite understandably)
}
int main()
{
SomeClass a;
a.someMemberFunction(); // Ok; it is defined above.
SomeNamespace::someFreeFunction(); // Undefined!
return 0;
}
So my question: is the above way of definining SomeClass::someMemberFunction() legal, and where in the spec is this mentioned? If legal, is it advisable? It certainly cuts down on clutter! :)
Many thanks :)
Perhaps I'm getting this wrong but if you have:
// example.h
namespace SomeNamespace
{
class SomeClass
{
public:
void someMemberFunction();
};
void someFreeFunction();
};
You can also simply write:
#include "example.h"
// example.cpp
namespace SomeNamespace
{
void SomeClass::someMemberFunction()
{
}
void someFreeFunction()
{
}
}
When you define a member-function, the compiler realizes that it is a member-function that must belong to a previously declared class, so it looks that class up, as specified in Section 9.3.5 of the standard:
If the definition of a member function is lexically outside its class
definition, the member function name shall be qualified by its class
name using the :: operator. [Note: a name used in a member function
definition (that is, in the parameter-declaration-clause including
the default arguments (8.3.6), or in the member function body, or, for
a constructor function (12.1), in a mem-initializer expression
(12.6.2)) is looked up as described in 3.4. ] [Example:
struct X {
typedef int T;
static T count;
void f(T);
};
void X::f(T t = count) { }
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. In the function definition, the parameter
type T refers to the typedef member T declared in class X and the
default argument count refers to the static data member count
declared in class X. ]
Basically, what you are doing is fine. However, there is another (preferable) way to cut down on the clutter when using nested namespaces, or namespaces with long names (or both) - define an alias:
namespace short_name = averylong::nested::namespacename;
Related
Consider following code snippet:
enum class Bar {
A
};
void foo(Bar) {}
struct Baz {
void foo() {
foo(Bar::A);
}
};
It fails to compile, the message from gcc 9.2 is:
:12:19: error: no matching function for call to 'Baz::foo(Bar)'
12 | foo(Bar::A);
|
I don't suspect it is a bug since clang 10 also fails. I have two questions regarding this situation:
Where does standard define bahaviour for such overloads?
What are the possible reasons that compiler behaviour is specified that way?
live example
The call to foo inside Baz::foo() will only look up names inside the class. If you mean to use the foo declared outside the class Baz, you need to use the scope-resolution operator, like this:
enum class Bar {
A
};
void foo(Bar) {}
struct Baz {
void foo() {
::foo(Bar::A); // looks up global 'foo'
}
};
Note that the unscoped call to foo fails because there is a Bar::foo that is found in the closest scope. If you name the function differently, then no function is found in Bar, and the compiler will look in the outer scope for the function.
enum class Bar {
A
};
void foo(Bar) {}
struct Baz {
void goo() { // not 'foo'
foo(Bar::A); // this is fine, since there is no 'Bar::foo' to find
}
};
Here's the quote from cppreference for a class definition.
e) 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.
Of course, this only applies to class definitions, but for member functions (which is your example), it says
For a name used inside a member function body, a default argument of a member function, exception specification of a member function, or a default member initializer, the scopes searched are the same as in [class definition], ...
So the same logic applies.
According to the rule of unqualified name lookup, from the standard, [basic.lookup.unqual]/1,
(emphasis mine)
In all the cases listed in [basic.lookup.unqual], the scopes are searched for a declaration in the order listed in each of the respective categories; name lookup ends as soon as a declaration is found for the name.
That means the name foo is found at the class scope (i.e. the Baz::foo itself), then name lookup stops; the global one won't be found and considered for the overload resolution which happens later.
About your 2nd question, functions can't be overloaded through different scopes; which might cause unnecessary confusion and complexity. Consider the following code:
struct Baz {
void foo(int i) { }
void foo() {
foo('A');
}
};
You know 'A' would be converted to int then passed to foo(int), that's fine. If functions are allowed to be overloaded through scopes, if someday a foo(char) is added in global scope by someone or library, behavior of the code would change, that's quite confusing especially when you don't know about the adding of the global one.
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(){}
I have a following snippet code of c++. Declared a class inside main() function.
What is the reason to we can not define friend function in local class?
#include<iostream>
int main()
{
class Foo
{
void foo() {} // Ok
friend void Bar(){}; // Error
};
}
There's a practical reason. First and foremost, an inline friend definition cannot be found by either qualified or unqualified lookup. It can only by found by ADL. So if we take the class from your example, put it in global scope and try to call Bar:
class Foo
{
friend void Bar(){};
void foo() {
Bar();
}
};
We'll be notified that Bar was not declared in that scope. So if it was in a local class. You can't call it from the members. You can't call it inside the function. The only way you may call it involves either some hoops or ADL. So the language just doesn't allow for it. It's not deemed a useful feature.
There is no convincing technical reason for this. ADL can't find it, you say? Well, that's basically part of the question: why can't ADL find it? Just extend ADL to make it find it.
One design-level reason for this limitation is probably rooted in the language treatment of unqualified names in friend declarations.
Unqualified names used in friend declarations in local classes refer to names from nearest enclosing non-class scope. This treatment of unqualified names is critically important, since this is the only way local classes can refer to each other (since for obvious reasons, local classes do not have qualified names)
int main()
{
class B;
class A {
int x;
friend B; // refers to local `B`
};
class B {
void foo(A &a) { a.x = 42; }
};
}
This rule is also applied to friend function declarations with unqualified names. C++ does not have local functions, but such friend declarations can still refer to a local non-defining declaration of a function (which is perfectly legal)
void foo() {}
int main()
{
void foo(); // refers to `::foo`
class A {
friend void foo(); // refers to local `foo`, which is `::foo`
};
}
Now, what would you propose should happen when one defines a friend function in a local class (using an unqualified name, of course)? What function is introduced by such a declaration? Into what scope, specifically? By definition, it is not a member of the class, since friend declarations do not introduce class members. It cannot be a member of the nearest enclosing local scope, since that would make it a local function and C++ does not support local functions.
We cannot just uniformly change the behavior of all unqualified names in friend declarations and say that they should now refer to names in the nearest enclosing namespace scope, since that would leave as with no way to refer to local classes (as shown above).
The only way out of this situation is to make only in-class friend function definitions refer to (and define) functions in the nearest enclosing namespace scope. Such functions would only be callable through [modified] ADL (and let's say we are OK with that). But that would mean that we'd have to give different treatment to unqualified names in friend function definitions (as opposed to non-defining friend declarations). This would be rather inelegant and confusing. So, the language authors decided against it.
Note that importance of this might have increased notably after C++14, which gave us deduced auto return types in functions. After that local classes became not even nearly as "local" as they used to be
auto foo()
{
struct S // Local class
{
void bar() {}
};
return S();
}
int main()
{
auto a = foo();
a.bar(); // An object of local class used outside of its original scope
typedef decltype(a) S; // Local type is "stolen" from its original scope
S b; // and used to freely declare objects in a completely
b.bar(); // different scope
}
Because member functions of a local class have to be defined entirely inside the class body and friend function not a member function. We declared friend functions inside class and defined outside of class.
According to cppreference:
Local classes
A local class cannot have static members
Member functions of a local class have no linkage
Member functions of a local class have to be defined entirely inside the class body
Local classes other than closure types (since C++14) cannot have member templates
Local classes cannot have friend templates
Local classes cannot define friend functions inside the class definition
A local class inside a function (including member function) can access the same names that the enclosing function can access.
I write some header file. I want separately declare the namespaces hierarchy (for clarity), and and then declare functions and classes. For me it looks as a table of contents in the document. It would be very convenient for me: to see the full hierarchy of namespaces in one place. I write this:
// Namespaces hierarchy:
namespace Bushman{
namespace CAD_Calligraphy{}
//...
}
// Declarations of classes and functions
class Bushman::CAD_Calligraphy::Shp_ostream{
public:
explicit Shp_ostream(std::ostream& ost);
};
But MS Visual Studio shouts on such way of creation of the header file. I should write so:
namespace Bushman{
namespace CAD_Calligraphy{
class Shp_istream{
public:
explicit Shp_istream(std::istream& ist);
};
}
}
Why the first variant doesn't work? Is this restriction of the C++, or IDE?
P.S. My additional question is here.
Thank you.
The restriction is in §9/1: "If a class-head-name contains
a nested-name-specifier, the class-specifier shall refer to
a class that was previously declared directly in the class or
namespace to which the nested-name-specifier refers[...]". In
other words, the first appearance of the class name cannot be in
something like Bushman::CAD_Calligraphy::Shp_ostream.
What you can do is add forward declarations in your initial
declaration of the hierarchy:
// Namespaces hierarchy:
namespace Bushman{
namespace CAD_Calligraphy{
class Shp_ostream;
//...
}
//...
}
// Declarations of classes and functions
class Bushman::CAD_Calligraphy::Shp_ostream{
public:
explicit Shp_ostream(std::ostream& ost);
};
Depending on how your headers are organized, this might even be
better from the human point of view: your header starts with
a sort of index of what is defined in it.
To quote the standard: Section 7.3.1.2 point 2:
Members of a named namespace can also be defined outside that
namespace by explicit qualification (3.4.3.2) of the name being
defined, provided that the entity being defined was already declared
in the namespace and the definition appears after the point of
declaration in a namespace that encloses the declaration’s namespace.
namespace Q {
namespace V
void f();
}
void V::f() { /∗ ... ∗/ } // ok.
void V::g() { /∗ ... ∗/ } // Error: g() is not yet a member of V
namespace V
void g();
}
}
namespace R {
void Q::V::g() { /∗ ... ∗/ } // // error: R doesn’t enclose Q
}
So, you could do what you have in your original post, if you declare the class name there:
namespace Bushman{
namespace CAD_Calligraphy {
class Shp_ostream;
...
}
}
That's how C++ works.
It's consistent with other nested declarations: you can't add members to a class from outside the class:
class A
{
};
void A::f() { } // Error!
And you can't add enumerators to an enum from outside:
enum E { E1 = 1, E2 = 2 };
E::E3 = 3; // Error!
You need to "open" the scope and declare the entity inside the scope. Once it's declared you can define it outside that scope, using a nested-name:
class A
{
void f(); // declare
};
void A::f() { } // define
First of all, C++ is not designed to work like that. So it is not a surprise that this is happening.
But, since you're using Visual Studio, you could take advantage of partial classes. Unfortunately, it seems this characteristic is only related to C++/CX so maybe yo won't be able to use it.
You will still need to declare a partial class in your namespace hierarchy, but I guess it could be empty.
To be honest, I haven't used this feature and I don't know how far can it be bent in order to achieve what you want. But you could anyway give it a try.
Remember that this is a Visual Studio extension, so your code won't be cross-platform.
Hope this helps. Somehow.
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;
}
}