I am new to C++.
I have a file that has the following:
namespace A {
namespace B {
function foo() {
}
}
function bar() {
}
}
and another file has the following:
namespace A {
namespace C {
// Call foo() and bar() here.
}
}
If I want to call foo and bar inside of namespace C, should I include their absolute namespace?
A::B::foo();
A::bar();
or I don't have to include the namespace A since they are all inside A?
B::foo();
bar();
This is a name lookup question.
So if you've read this, you'll know the difference between Unqualified Lookup and Qualified Lookup
So obviously, unqualified lookup is valid here, but if you want to do some work like disambiguation, you may use qualified lookup. So, qualified lookup is always valid when unqualified lookup is valid.(If you can use qualified lookup).
Just little addition. As Constructor said, qualified lookup always generates well-formed code, but that code does not always produce an expected result. Consider this disambiguation example
#include <iostream>
void foo();
void foo(float);
namespace Boo {
using ::foo;
void foo(int a) { std::cout << __PRETTY_FUNCTION__ << " is here!\n"; }
}
void foo() { std::cout << __PRETTY_FUNCTION__ << " is here!\n"; }
void foo(int a) { std::cout << __PRETTY_FUNCTION__ << " is here!\n"; }
void foo(float) { std::cout << __PRETTY_FUNCTION__ << " is here!\n"; }
using namespace Boo;
int main(int argc, char *argv[])
{
foo(); // no error!
Boo::foo(); // still same
//foo(3); // aw, there are three of them. Bad, bad `using namespace`!
Boo::foo(3);
Boo::foo(3.f);
return 0;
}
namespace Boo propagates name foo to be Boo::foo. We had defined foo() after namespace declaration, but prototype declaration required to be known before.
Now imagine that Boo is std, foo prototypes are something like abs or sin from standard header and are declared that way. Header implementations are allowed to use trick from above. Result of re-definition of names used in standard namespace is described as undetermined, because depending of if using was in implementation or not, the program would use standard or user-defined function with no regard to qualified name.
TL;DR: Result of qualified lookup is always correct but is not always well-determined if reserved names are not respected.
Related
I thought that in a nested namespace, anything that is part of the parent (or global) namespace is considered equally for overload resolution, but this example seems to show otherwise.
This works fine:
#include <iostream>
void foo(int) { std::cout << "int\n"; }
void foo(float) { std::cout << "float\n"; }
namespace NS {
void bar() {
foo(0);
}
}
int main() {
NS::bar();
}
The call to foo(0) matches foo(int) since it is a better match and everything works as expected. However, if I move the declaration of foo(float) into the namespace:
#include <iostream>
void foo(int) { std::cout << "int\n"; }
namespace NS {
void foo(float) { std::cout << "float\n"; }
void bar() {
foo(0);
}
}
int main() {
NS::bar();
}
The call to foo(0) now calls foo(float)!
I have searched through https://en.cppreference.com/w/cpp/language/overload_resolution and many other such pages to find the rule that explains this, but I seem to be missing it. Can someone please explain which of the many complex overload resolution rules causes this, or is it something else?
EDIT
I just discovered it is even weirder. Even if the foo inside the namespace doesn't match at all, it still won't use the one outside. This just completely fails to compile:
#include <iostream>
void foo(int) { std::cout << "int\n"; }
namespace NS {
void foo(float, float) { std::cout << "float\n"; }
void bar() {
foo(0);
}
}
int main() {
NS::bar();
}
The point is name lookup, which happens before overload resolution.
When the name foo is found at the namespace NS, name lookup stops, the further scopes won't be checked, the global foo won't be found at all. Then there's only one candidate in overload resolution, and int could convert to float implicitly, then NS::foo(float) gets called at last.
(emphasis mine)
name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.
I don't understand why I get the error "ambiguous call to overloaded function".
Before "main", I declared to use namespace "second".
My expected output is:
this is the first foo
this is the second foo
this is the second foo
#include <iostream>
using namespace std;
namespace first {
void foo() {
cout << "this is the first foo" << endl;
}
}
namespace second {
void foo() {
cout << "this is the second foo" << endl;
}
}
void foo() {
cout << "this is just foo" << endl;
}
using namespace second;
void main() {
first::foo();
second::foo();
foo();
}
Before "main", I declared to use namespace "second".
When you do this, second::foo is introduced into the global namespace, then for foo(); both second::foo and ::foo are valid candidates.
You can specify that you want to call the global foo explicitly, i.e.
::foo();
Or use using-declaration inside main() instead of using-directive, e.g.
int main() {
using second::foo;
first::foo();
second::foo();
foo();
}
The reason this is happening is because of your: using namespace second;
When you do this you qualify the function foo() from the second namespace into the global scope. In the global scope, there exists another function foo() with the exact same signature. Now, your calls to first::foo() and second::foo() are fine. However, when you get to your call to foo(), the compiler doesn't know whether it should call just foo() or second::foo() since they are ambiguous, and at this point they are both in the global namespace.
Your using namespace second; is precisely the reason you get the error. It practically tells the compiler to treat second::foo as if it was in the global namespace. So now you have two foos there.
By the way, void main is not valid C++. It must be int main.
Firstly, replace void main() { } with
int main() {
return 0;
}
Secondly, using namespace second; should be inside main() from where you want to call particular namespace, not globally.
Finally, If you are using ::scope resolution operator then you don't have to mention using namespace second in the main(), use either one.
Just do like below
int main() {
first::foo(); /* first foo will be called */
second::foo(); /* second foo() will be called */
foo(); /* global foo() will be called */
return 0;
}
The following example is given in N4296::13.3.3 [over.match.best]
namespace A
{
extern "C" void f(int = 5);
}
namespace B
{
extern "C" void f(int = 5);
}
using A::f;
using B::f;
void use()
{
f(3); // OK, default argument was not used for viability
f(); // Error: found default argument twice
}
I tried to write something similar:
#include <iostream>
namespace A
{
void foo(int a = 5){ std::cout << a << "1" << std::endl; }
}
namespace B
{
void foo(int a = 5){ std::cout << a << std::endl; }
}
using A::foo;
using B::foo;
int main()
{
foo(2); //Error
}
DEMO
But I got a compile-time error. Why does the Standard says that it's OK?
The difference is the extern "C", which affects namespace membership of the function:
From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1997/N1138.pdf
What remains is the definition of “same entity” with respect to ‘extern “C”’ language linkage? This is
addressed by 7.5¶6:
“At most one function with a particular name can have C language linkage. Two
declarations for a function with C language linkage with the same function name
(ignoring the namespace names that qualify it) that appear in different namespace scopes
refer to the same function. Two declarations for an object with C language linkage with
the same name (ignoring the namespace names that qualify it) that appear in different
namespace scopes refer to the same object.”
That's because the two functions are imported from their namespace, this means that the same function has 2 definitions, you can solve it like this:
#include <iostream>
namespace A
{
void foo(int a = 5){ std::cout << a << "1" << std::endl; }
}
namespace B
{
void foo(int a = 5){ std::cout << a << std::endl; }
}
int main()
{
A::foo(2);
B::foo(3);
}
I'm writing some template code to determine if a given type can be passed as any argument to any available overload of a function. In the example below I've used the log function, but I've also tried this code on others in the math library, and the results are the same. The idea is to use function overloading and the sizeof operator to distinguish between cases where the type in question can legally be passed to the function in question (log, in this example).
If it worked, we'd have sizeof(overload<type>(NULL)) == sizeof(True) when 'type' can be legally passed to log, and sizeof(overload<type>(NULL)) == sizeof(False) otherwise. This does seems to work for most types, but fails for std::string.
Here's exactly how it fails:
Under normal circumstances we have sizeof(overload<std::string>(NULL)) == sizeof(False), as we should. But, when I declare an overload of log that does take a string, it still doesn't trigger the sizeof(True) branch of the logic. Note that I don't actually want to declare log(std::string) function, I'm just testing this code to make sure that it's able to detect all possible overloads.
At first I thought it just wasn't detecting overloads properly, but when I tried it with a user-defined class ('MyClass' in the example below), it worked fine: it produced sizeof(True) when log(MyClass) was declared, and sizeof(False) otherwise.
#include <iostream>
#include <math.h>
template<int>
struct TakesInt{};
struct True
{
};
struct False
{
// guarantees that sizeof(False) != sizeof(True)
True array[2];
};
// takes anything; fall back if no match can be found
template<typename T>
False overload(...);
// takes a specific type; does not actually call log
template<typename T>
True overload(TakesInt<sizeof(log(T()))>*);
// As a test, this is an overload of log that takes a string.
// I don't actually want to implement this, but it should make the compiler
// think that a string is a valid argument.
double log(std::string);
// a placeholder for user defined class; could really be anything,
// like an arbitrary number class
struct MyClass{};
// declaring log for the arbitrary class above
// note that this is the same as for the log(std::string)
// if one works, the other should
double log(MyClass);
int main()
{
std::cout << sizeof(True) << '\t' << sizeof(False) << std::endl;
std::cout << sizeof(overload<std::string>(NULL)) << std::endl;
std::cout << sizeof(overload<double>(NULL)) << std::endl;
std::cout << sizeof(overload<MyClass >(NULL)) << std::endl;
return 0;
}
Here's the same issue w/o the SFINAE distraction:
#include <iostream>
namespace ns
{
struct string {};
}
void bar(...) { std::cout << "void bar(...)\n"; }
template<class T>
void foo()
{
T x{};
bar(x);
}
void bar(ns::string) { std::cout << "void bar(ns::string)\n"; }
int main()
{
foo<int>();
foo<ns::string>();
}
Output:
void bar(...)
void bar(...)
Lookup of a dependent function name will be performed:
as (pure) unqualified lookup from the point of definition
as (pure) argument-dependent lookup from the point of instantiation
Therefore, the following example differs:
#include <iostream>
namespace ns
{
struct string {};
}
void bar(...) { std::cout << "void bar(...)\n"; }
template<class T>
void foo()
{
T x{};
bar(x);
}
namespace ns
{
void bar(ns::string) { std::cout << "void bar(ns::string)\n"; }
}
int main()
{
foo<int>();
foo<ns::string>();
}
Output:
void bar(...)
void bar(ns::string)
For std::string, the only associated namespace is std. The global namespace is not associated and will not be searched in the OP's code. Therefore, the overload declared after the template definition will not be found.
N.B. Please do not inject overloads into namespace std. This will lead to undefined behaviour as per [namespace.std]/1.
Over the weekend, I had specific problem with function overload resolution that I can't seem to solve.
The code below is a distillation of the problem:
#include <iostream>
using namespace std;
template<typename T>
void f(const T& t)
{
cout << "In template function." << endl;
}
class C
{
public:
void f() { cout << "In class function." << endl; }
void g() { int i=0; f(i); }
void h() { int i=0; f<int>(i); }
void i() { extern void f(int); int i=0; f(i); }
};
int main()
{
cout << "Test" << endl;
C c;
c.i();
return 0;
}
1) C::g won't compile because the compiler won't try the template. It just complains that there is no C::f to match.
2) C::h won't compile for no reason that is obvious to me. The message is "expected primary-expression before 'int'"
3) C::i will compile, but (after commenting out g and h) it won't link to anything. I think I understand this: the extern is forcing the linker to look into another compilation unit, but any template definition would be in this compilation unit.
I would appreciate any clarification on the reasons for 1 and 2. Also, ultimately, can someone suggest a way to get this to work that doesn't involve creating another compilation unit?
Likely it is finding C::f instead of global f. Use ::f<int>(i).
Look here: http://ideone.com/zs9Ar
Output:
Test
In template function.
#include <iostream>
using namespace std;
template<typename T>
void f(const T& t)
{
cout << "In template function." << endl;
}
class C
{
public:
void f() { cout << "In class function." << endl; }
void g() { using ::f; int i=0; f(i); }
};
int main()
{
cout << "Test" << endl;
C c;
c.g();
return 0;
}
Names in a smaller scope hide names in an outer scope.
Use ::f to indicate global namespace.
In i() you declare a function called f, but indeed there is no definition (it is not the same as the template), so you get a linker error.
C++ is somewhat "greedy" when trying to find functions. As soon as it finds a matching function name in the current scope (in this case, class C) it stops and then tries to match the parameters. If the parameters don't match, it won't try additional scopes. I assume this was to keep compiler writers sane. That's why g doesn't compile.
The same thing applies to h. It sees a non-template function f in the class scope and gets confused. It thinks you're trying to do a < comparison against the function C::f.
In both cases you can use ::f to qualify the name to the global scope.
Functions with the same name will hide other functions of the same name when they have different scopes, even if they have different signatures.
Instead of using a template for the first f, you could just do f(int) and the result would be the same for #1(the C::f() hides the ::f(int)).
One solution is to add "::" before the name to force the global namespace.
Another solution would be to change the names.