Does the "using" keyword have different effects in the context of defining member and non-member functions? The example code below suggests to me that it might.
main.cpp
#include "baz.h"
int main()
{
foo::bar x;
x.baz();
foo::foo_non_member();
}
baz.h
namespace foo
{
class bar
{
public:
bar() = default;
void baz();
};
void foo_non_member();
};
baz.cpp
#include "baz.h"
#include<iostream>
using namespace foo;
void bar::baz()
{
std::cout << "baz\n";
}
namespace foo
{
void foo_non_member()
{
std::cout << "non-member\n";
}
}
The above code compiles and runs.
$> g++ main.cpp baz.cpp; ./a.out
baz
non-member
If I remove the using namespace foo; from baz.cpp, I get a compiler error.
$> g++ main.cpp baz.cpp
baz.cpp:5:6: error: ‘bar’ has not been declared
void bar::baz()
If I put that using statement back in and move the definition of foo_non_member() outside of the foo namespace, I get a linker error.
$> g++ main.cpp baz.cpp
/tmp/ccHeSwsZ.o: In function `main':
main.cpp:(.text+0x24): undefined reference to `foo::foo_non_member()'
collect2: error: ld returned 1 exit status
Why does the using keyword appear not to have the same effect here for bar::baz() and foo_non_member()?
For this part:
using namespace foo;
void bar::baz()
{
std::cout << "baz\n";
}
The using namespace foo; is used for the lookup of the bar:: part, and due to that the compiler is able to tie the definition of void bar::baz() to the declaration in the namespace foo.
And if you remove using namespace foo; it is not able to find bar.
If I put that using statement back in and move the definition of foo_non_member() outside of the foo namespace, I get a linker error.
void foo_non_member()
{
std::cout << "non-member\n";
}
Here foo_non_member not have any relation to bar:: or anything else (according to the specs) that would allow the compiler to figure out that this definition is related to the declaration in the namespace foo.
The standard committee for sure could have added some rules to the specification to allow the compiler to get the foo_non_member definition and the declaration together if the using namespace foo; is present but they decided to don't do so.
The reason for that is likely because you then would have the ambiguity about whether you want to define a new void foo_non_member() outside of the namespace foo or if you want to have a definition for void foo_non_member() of foo.
Related
Suppose we have a class foo from a namespace space which declares a friend function named bar, which is later on defined, like so:
namespace space {
struct foo {
friend void bar(foo);
};
}
namespace space {
void bar(foo f) { std::cout << "friend from a namespace\n"; }
}
To my understanding, friend void bar(foo); declares bar to be a free function inside space taking a foo by value. To use it, we can simply do:
auto f = space::foo();
bar(f);
My understanding is that we don't have to say space::bar, because ADL will see that bar is defined in the same namespace as foo (its argument) and allow us to omit the full name qualification. Nonetheless, we are permitted to qualify it:
auto f = space::foo();
space::bar(f);
which works (and should work) exactly the same.
Things started to get weird when I introduced other files. Suppose that we move the class and the declaration to foo.hpp:
#ifndef PROJECT_FOO_HPP
#define PROJECT_FOO_HPP
namespace space {
struct foo {
friend void bar(foo);
};
}
#endif //PROJECT_FOO_HPP
and the definitions to foo.cpp:
#include "foo.hpp"
#include <iostream>
namespace space {
void bar(foo f) { std::cout << "friend from a namespace\n"; }
}
notice that all I did was I moved (didn't change any code) stuff to a .hpp-.cpp pair.
What happened then? Well, assuming that we #include "foo.hpp", we still can do:
auto f = space::foo();
bar(f);
but, we are no longer able to do:
auto f = space::foo();
space::bar(f);
This fails saying that: error: 'bar' is not a member of 'space', which is, well, confusing. I am fairly certain that bar is a member of space, unless I misunderstood something heavily. What's also interesting is the fact that if we additionally declare (again!) bar, but outside of foo, it works. What I mean by that is if we change foo.hpp to this:
#ifndef PROJECT_FOO_HPP
#define PROJECT_FOO_HPP
namespace space {
struct foo {
friend void bar(foo);
};
void bar(foo); // the only change!
}
#endif //PROJECT_FOO_HPP
it now works.
Is there something with header / implementation files that alters the expected (at least for me) behaviour? Why is that? Is this a bug? I am using gcc version 10.2.0 (Rev9, Built by MSYS2 project).
There's a slight subtlety that the friend declaration, while it doesn't require a previous declaration of the function or class your class is befriending, does not make the function visible for lookup except via ADL.
cppreference:
A name first declared in a friend declaration within a class or class template X becomes a member of the innermost enclosing namespace of X, but is not visible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at the namespace scope is provided - see namespaces for details.
This is why you're able to find bar(f) (performs ADL) but not space::bar(f) (fully qualifying the name means ADL is not invoked).
Calling code that doesn't find bar via ADL needs to see a declaration. In the version where everything is in one file, calling code will see the entire definition of space::foo. When you split it into an HPP and a CPP file, calling code only sees the friend declaration which provides limited accessibility.
As you identified, if you want to make the function visible via ordinary lookup, put a declaration of foo in "foo.hpp":
#ifndef PROJECT_FOO_HPP
#define PROJECT_FOO_HPP
namespace space {
struct foo {
friend void bar(foo);
};
void bar(foo); // Now code that includes foo.hpp will see a declaration for bar
}
#endif //PROJECT_FOO_HPP
Single File Example
Here is a simple program using namespaces.
#include <iostream>
namespace foo {
void hello();
}
void foo::hello() {
std::cout << "hello\n";
}
void foo::hello(); // Why is this syntax allowed? When is it useful?
int main() {
foo::hello();
}
This program compiles fine and produces the expected output.
$ ./a.out
hello
I want to know when is the void foo::hello(); declaration useful? In this program, clearly this declaration is redundant. But since this syntax exists, this must be useful in some other scenario?
Two-File Example
Here is an example that shows that the void foo::hello(); declaration standing alone is useless.
// foo.cpp
#include <iostream>
namespace foo {
void hello();
}
void foo::hello() {
std::cout << "foo::hello\n";
}
// main.cpp
void foo::hello(); // This does not work!
int main()
{
foo::hello();
}
Trying to compile the above two files leads to the following errors:
$ clang++ foo.cpp main.cpp
main.cpp:1:6: error: use of undeclared identifier 'foo'
void foo::hello();
^
main.cpp:5:5: error: use of undeclared identifier 'foo'
foo::hello();
^
2 errors generated.
The only way to fix main.cpp in the above example seems to be include the namespace declaration:
// main.cpp - fixed
namespace foo {
void hello();
}
void foo::hello(); // But now this is redundant again!
int main()
{
foo::hello();
}
So after we get this code to compile properly, the void foo::hello(); declaration seems redundant again. Is there any scenario where such a declaration would be playing a useful role?
In most cases in C++, for anything that can be either declared without defining it or can be completely defined, a declaration or a definition of that thing can appear in all the same contexts. So this is probably just a way of keeping the pattern consistent.
The C++ Standard does not go out of its way to forbid things that are a logical consequence of its other rules but just not useful, as long as it's reasonably clear what will happen if someone does it anyway. If it did add these restrictions, that would put extra work on compiler writers for no real benefit.
From [basic.def]/1
A declaration 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.
Which allows code like this
#include <iostream>
void foo();
void foo();
void foo();
void foo();
void foo();
int main()
{
foo();
}
void foo() { std::cout << "foo()"; }
To be valid. There is no harm in having multiple declarations of a function, as long as we have only one definition, it won't cause an issue.
Another example would be you have a global function you want to be a friend of multiple classes. You would include that function prototype in each class header so you can friend it and then you would include all of those class headers in your main source file. So
A.h
void foo();
struct A { friend void foo(); }
B.h
void foo();
struct B { friend void foo(); }
main.cpp
#include "A.h"
#include "B.h"
...
and that would be converted to
main.cpp
void foo();
struct A { friend void foo(); }
void foo();
struct B { friend void foo(); }
...
So we would want this to be legal.
//file.h
namespace first
{
namespace second
{
void foo();
}
}
//file.c
using namespace first::second;
void foo()
{
...
}
//main.c
using namespace first::second;
int main()
{
foo();
}
the code above doesn't work as the compiler didn't recognize the foo(). where is my mistake?
try this:
This puts the implementation into the namespace
//file.c
namespace first
{
namespace second
{
void foo()
{
...
}
}
}
This tells main explicitly where to find foo:
//main.c
int main()
{
::first::second::foo();
}
I'm going to guess that you got an unresolved linking error when you tried to call foo from main in the example you posted. There are couple issues at play here starting from the top:
file.h declares a foo existing in namespace first::second.
file.c brings namespace first::second into filescope lookup but it does not affect function definitions. Thus the implementation of void foo() {} is actually a function defined in global scope -- not in first::second as you might expect.
main.c brings namespace first::second into its filescope. The compiler will consider first::second as well as global scope :: when you call foo in main. The compiler chooses first::second::foo since file.h doesn't declare the global foo().
you get a linking error for unresolved symbol because first::second::foo was never implemented.
In addition to Jay's suggestion, the other fix you can do is to fully qualify foo's definition similar to member functions:
// file.c
#include "file.h"
void first::second::foo()
{
// ...
}
What is the correct way to call one function from another from the same namespace when using the 'using namespace' keyword in the implementation? I get following error:
Call to 'bar' is ambiguous
when compiling this:
// Foo.h
namespace Foo
{
void bar();
void callBar();
}
// Foo.cpp
#include "Foo.h"
using namespace Foo;
void bar() {/* do something */}
void callBar() {bar();}
It appears that you are providing definitions of bar and callBar in the cpp file. In this case you should put the functions in the namespace Foo where they are declared, rather than importing that namespace with using:
#include "Foo.h"
namespace Foo {
void bar() {/* do something */}
void callBar() {bar();}
}
The using namespace directive tells the compiler that you want to call functions and refer to classes from the namespace Foo without qualifying their names explicitly; you can have multiple such directives in your file. It does not tell the compiler that the definitions that you provide below should belong to the namespace Foo, so the compiler dumps them in the top-level namespace.
The end result is that the compiler sees two bars - the Foo::bar() declared in the Foo namespace, with external definition, and ::bar() defined in your cpp file in the default namespace.
You have two bars here. one declared in namespace Foo but not defined and another declared and defined in the global namespace. Both are reachable from the call site because you are using using namespace Foo;, hence the ambiguity for the compiler.
If the definitions of the functions are for the ones in the Foo namespace then you should put them in there too.
namespace Foo {
void bar() {/* do something */}
void callBar() {bar();}
}
When defining a function signature in an anonymous namespace within a .hpp, is it valid to place the implementation of that function within the .cpp? When I do so I get an undefined reference error.
Example:
//hpp
#ifndef __BAR_HPP_
#define __BAR_HPP_
namespace foo
{
namespace
{
struct Bar
{
void func();
};
}
}
#endif
//cpp
using foo;
void Bar::func()
{
//...
}
Think of this:
namespace foo
{
struct Bar
{
void func();
};
}
void Bar::func() { /*impl...*/ }
Your code doesn't work for the same reason this code doesn't -- the definition is being provided in the wrong scope. What's needed is:
void foo::Bar::func() { /*impl...*/ }
But what do you put in place of foo:: to refer to the name of an anonymous namespace? It doesn't have one.
Bottom line: it's not possible to declare something inside of an anonymous namespace then define it elsewhere, as no mechanism exists for specifying the proper scope.