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.
Related
This question got me wondering whether it is ever useful/necessary to fully qualify class names (including the global scope operator) in an out-of-class member function definition.
On the one hand, I've never seen this done before (and the syntax to properly do so seems obscure). On the other, C++ name lookup is very non-trivial, so maybe a corner case exists.
Question:
Is there ever a case where introducing an out-of-class member function definition by
ReturnType (::Fully::Qualified::Class::Name::MemberFunctionName)(...) { ... }
would differ from
ReturnType Fully::Qualified::Class::Name::MemberFunctionName(...) { ... } (no global scope :: prefix)?
Note that member function definitions must be put into a namespace enclosing the class, so this is not a valid example.
A using-directive can cause Fully to be ambiguous without qualification.
namespace Foo {
struct X {
};
}
using namespace Foo;
struct X {
void c();
};
void X::c() { } // ambiguous
void ::X::c() { } // OK
It's necessary if one is a masochist and enjoys writing stuff like this
namespace foo {
namespace foo {
struct bar {
void baz();
};
}
struct bar {
void baz();
};
void foo::bar::baz() {
}
void (::foo::bar::baz)() {
}
}
One can of course write the second overload as foo::foo::bar::baz in global scope, but the question was whether or not the two declarations can have a different meaning. I wouldn't recommend writing such code.
If a using directive is used then there can be a confusing code.
Consider the following demonstrative program
#include <iostream>
#include <string>
namespace N1
{
struct A
{
void f() const;
};
}
using namespace N1;
void A::f() const { std::cout << "N1::f()\n"; }
struct A
{
void f() const;
};
void ::A::f() const { std::cout << "::f()\n"; }
int main()
{
N1::A().f();
::A().f();
return 0;
}
So for readability this qualified name
void ::A::f() const { std::cout << "::f()\n"; }
shows precisely where the function is declared.
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.
I have to define two functions, say, foo() and bar() in the same namespace and the same file. For the definition of the first, foo(), I want to use all symbols of, say, namespace other, but don't want symbols from namespace other to be automatically in scope for my other function, bar(). Is this possible? How?
(note: I don't want to know about alternative "solutions" either avoiding this problem of mitigating it, such as namespace o=other etc.)
Yes, it is possible:
void foo()
{
using namespace abc;
....
}
or
void foo()
{
using abc::x;
using abc::y;
using abc::z;
....
}
#include <iostream>
void quux() { std::cout << "root\n"; }
namespace other {
void quux(int x = 0) { std::cout << "other\n"; }
}
namespace taxes {
void foo() {
using namespace other;
quux(3);
};
void bar() {
quux();
}
}
int main() {
taxes::foo();
taxes::bar();
}
Live example
Note that quux in bar would be ambiguous if it could see other::quux, but it cannot.
On the other hand, this does not give you access to namespace other in the 'head' of the function foo (the parameters etc), but that is a rare requirement. There might be a solution involving inline namespaces or the like, but probably not worth the confusion.
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.
What are the pro and cons of using two namespaces such as
namespace library1
{
void function1();
}
namespace library1_sublibrary1
{
void function1();
}
instead of
namespace library1
{
void function1();
namespace sublibrary1
{
void function1();
}
}
I would have to fully qualify symbols in the second case, right? Is there any concrete reason (beyond personal taste) why one should be preferred on the other?
Repeating from two comments.
Between the two versions (one: two separate namespaces, two: nested namespaces), there are some differences in name lookup. Most of these can be overcome with either a using-declaration (e.g. using outer::function0;) or a using-directive (e.g. using namespace library1;), but some cannot.
1. unqualified lookup inside the inner namespace
#include <iostream>
namespace outer
{
void function0() { std::cout << "outer::function0" << std::endl; }
namespace inner
{
void test0()
{
function0(); // finds outer::function
}
}
}
namespace another_outer
{
void test0_1()
{
// either
using namespace outer;
// or
using outer::function0;
function0();
}
}
N.B. you can also put the using-directive or using-declaration at namespace scope in another_outer, but some difference remains:
2. stopping unqualified lookup
Unqualified lookup stops in a scope once a name has been found (and then doesn't search the outer scopes). This can be used to hide functions from other scopes. Here's an example of a problem related to this; also see this answer.
void function1() { std::cout << "::function1" << std::endl; }
namespace another_outer
{
void function1() { std::cout << "another_outer::function1" << std::endl; }
}
namespace outer
{
namespace inner
{
void function1() { std::cout << "outer::inner::function1" << std::endl; }
}
void test1()
{
function1(); // finds ::function1
{
using namespace inner;
function1(); // finds (only) outer::inner::function1
}
{
using namespace another_outer;
//function1(); // finds both ::function1 and another_outer::function1
// error: ambiguous call
}
}
}
3. ADL
This isn't about differences between the two variants, but addresses "I would have to fully qualify symbols in the second case, right?".
Argument-dependent lookup happens when you don't qualify the name of a function in a function call. It looks for the name of the function in namespaces (and classes) associated with the arguments.
namespace outer
{
struct ADL {};
void function2(ADL&) { std::cout << "outer::function2" << std::endl; }
namespace inner
{
void function2(ADL const&);
void test2()
{
ADL x;
function2(x); // finds both outer::function2
// and outer::inner::function2
// overload resolution selects outer::function2
}
}
}
int main()
{
outer::ADL x;
function2(x); // finds outer::function2
outer::inner::test2();
// other tests:
outer::inner::test0();
outer::test1();
}
4. Specifically about conflicting symbols
If you have two identical functions (except for the return type) in outer and outer::inner and both are found for some call, that call will be ambiguous. But unqualified lookup might only find one of them:
namespace outer
{
void function3() { std::cout << "outer::function3()" << std::endl; }
namespace inner
{
void function3()
{ std::cout << "outer::inner::function3()" << std::endl; }
void test3()
{
function3(); // only finds outer::inner::function3
}
}
void test3_1()
{
using namespace inner;
//function3(); // finds both outer::function3
// and outer::inner::function3
// error: ambiguous call
using inner::function3;
function3(); // finds (only) outer::inner::function3
}
}
namespace another_outer
{
void function3() { std::cout << "another_outer::function3" << std::endl; }
void test3_1()
{
using namespace outer;
function3(); // still only finds another_outer::function3
using outer::function3;
function3(); // only finds outer::function3
}
}