How to write a different version of stl algorithms in c++? - c++

For practice, I wrote some template functions whose names are the same as the stl algorithms. But my code can not compile
error: Call to < algorithm_name > is ambiguous.
I only included using std::necessary_names; in my code rather than using namespace std;.

Usually when you have using, the "used" name takes precedence:
namespace N { int x = 0; }
int x = 1;
int main() {
using N::x;
cout << x;
}
// Output: 0
However, Argument-Dependent Lookup can mess this up:
namespace N {
struct T {};
void f(T) {}
}
namespace M {
void f(N::T) {}
}
int main() {
using M::f;
N::T o;
f(o); // <--- error: call of overloaded 'f(N::T&)' is ambiguous
}
So, if you are having trouble, qualify your own namespace (in this example, M) explicitly:
namespace N {
struct T {};
void f(T) { cout << "N::f"; }
}
namespace M {
void f(N::T) { cout << "M::f"; }
}
int main() {
using M::f;
N::T o;
M::f(o); // <--- Output: "M::f"
}
In a somewhat bizarre twist, you can also use parentheses to prevent ADL:
namespace N {
struct T {};
void f(T) { cout << "N::f"; }
}
namespace M {
void f(N::T) { cout << "M::f"; }
}
int main() {
using M::f;
N::T o;
(f)(o); // <--- Output: "M::f"
}
Explanation
[n3290: 3.4.1/1]: [re: unqualified name lookup] In all the cases
listed in 3.4.1, 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. If no declaration is
found, the program is ill-formed.
[n3290: 3.4.1/2]: [i.e. first priority] The declarations from the
namespace nominated by a using-directive become visible in a namespace
enclosing the using-directive; see 7.3.4. For the purpose of the
unqualified name lookup rules described in 3.4.1, the declarations
from the namespace nominated by the using-directive are considered
members of that enclosing namespace.
[n3290: 3.4.2/1]: [re: argument-dependent lookup] When the postfix-expression in a function call
(5.2.2) is an unqualified-id, other namespaces not considered during
the usual unqualified lookup (3.4.1) may be searched, and in those
namespaces, namespace-scope friend function declarations (11.3) not
otherwise visible may be found. These modifications to the search
depend on the types of the arguments (and for template template
arguments, the namespace of the template argument).
i.e. Normal lookup stops at the name that you brought into scope with using, but when ADL comes into play, other names are also added to the candidate set, causing an ambiguity between two names.

It's better to declare your own version in a namespace; so that such problem would not occur.
namespace MySTL
{
template<typename T, ... > // ... means other template params
class vector;
template<typename T, ... >
class queue;
...
}
now you can do,
using std::vector;
which will not collide with MySTL::vector.

Chances are that you are hitting a problem with Argument Dependent Lookup. When you pass a type that is defined within a namespace to an unqualified function, the namespaces of all the arguments are implicitly added to the lookup set, and that might cause collisions. You can try to qualify your own algorithm calls to inhibit ADL from kicking in.
namespace n {
struct test {};
void foo( test const & ) {}
};
int main() {
n::test t;
foo( t ); // Will find n::foo as the argument belongs to n namespace
}

Related

Confused about namespaces and Argument-Dependent Lookup in C++

I've been reading through the namespace chapter in The C++ Programming Language by Bjarne Stroustrup and got confused about how functions get called using Argument-Dependent Lookup. The following are code snippets from the book:
Snippet 1
namespace Chrono {
class Date { /* ... */ };
bool operator==(const Date&, const std::string&);
std::string format(const Date&); // make string representation
// ...
}
void f(Chrono::Date d, int i)
{
std::string s = format(d); // Chrono::format()
std::string t = format(i); // error: no format() in scope
}
This snippet makes sense to me since Chrono is a namespace used in the function f's arguments and therefore it is searched successfully for a format(Date) function. It also appears the function f and namespace Chrono share the same scope, which confuses me about the next snippet:
Snippet 2
namespace N {
struct S { int i };
void f(S);
void g(S);
void h(int);
}
struct Base {
void f(N::S);
};
struct D : Base {
void mf();
void g(N::S x)
{
f(x); // call Base::f()
mf(x); // call D::mf()
h(1); // error: no h(int) available
}
};
This makes sense to me up until the line "h(1);" Since both structs and namespace N share the same scope, why can't the function "void h(int)" be found in namespace N?
Stroustrup does go on to say that "If an argument is a member of a namespace, the associated namespaces are the enclosing namespaces." Since the argument to g is a member of namespace N, does this mean the enclosing namespace is the global namespace which does not contain a function "h(int)"? If that's the case, why wouldn't Snippet 1 fail if the enclosing namespace is the global namespace which also doesn't include a "format(Date)" function?
Thanks in advance for insight into this matter!
ADL applies based on the types of the arguments in the call itself, not the types of the parameters of the function the call may or may not be in.
In format(d), format is looked up in Chrono because an argument to that call, d, is of the type Chrono::Date, and Chrono is an associated namespace of that type. Whether the function containing the call is void f(Chrono::Date d, int i) or void f() is irrelevant. (Obviously, in the latter case, assuming that there's a Chrono::Date d;.)

Namespace set as Used because of One Type Inside being Used?

I just noticed this. I don't know why this is the case, if i use one element from a namespace i don't want anything else to be accessible without having to use the namespace. For example here, this code is valid:
namespace Test
{
struct Magic
{
int poof;
};
struct Magic2
{
int poof;
};
int Alakazam(const Magic& m)
{
return m.poof;
}
int Alakazam(const Magic2& m)
{
return m.poof;
}
};
using Magic = Test::Magic;
int main()
{
Alakazam(Magic()); // valid
Alakazam(Test::Magic2()); // valid
Test::Alakazam(Magic()); // what i want to only be valid
Test::Alakazam(Test::Magic2()); // this too
}
Any reasoning behind this? Does the spec state that this has to be true?
As suggested by immbis in the comment, this is defined by the standard:
3.4.2: Argument dependent name lookup
When the postfix-expression in a function call is an unqualified-id, other namespaces not considered during the usual
unqualified lookup may be searched, and in those namespaces,
namespace-scope friend function or function template declarations not
otherwise visible may be found. These modifications to the search
depend on the types of the arguments (and for template template
arguments, the namespace of the template argument).
...
If you want to defeat this mecanism, you have to use nested namespace like this, but it's tricky:
namespace Test
{
struct Magic
{
int poof;
};
struct Magic2
{
int poof;
};
namespace Test2 { // use a nested namespace that will not be searched autoamtically
int Alakazam(const Magic& m)
{
return m.poof;
}
int Alakazam(const Magic2& m)
{
return m.poof;
}
}
using namespace Test2; // but give some access to the enclosing namespace
};
Live Demo : Then, your two first calls will not be valid any longer. However, the last call in your example is still possible: you can't prevent the use of fully qualified names outside of the namespace.

Why does friend function found successfully via ADL

Consider the following code:
#include <stdio.h>
class A
{
public:
friend void foo(A a){ printf("3\n"); }
};
int main()
{
foo(A());
}
It works. But I thought that this code is invalid. It is because 3.4.1/3:
For purposes of determining (during parsing) whether an expression is
a postfix-expression for a function call, the usual name lookup rules
apply.
Usual name lookup rules could not find the friend function because name declared by friend is invisible in the global namespace in my case. Actually 3.3.1/4:
friend declarations (11.3) may introduce a (possibly not visible) name
into an enclosing namespace
This implies that the programm is ill-formed. It is because that there is no name which found during the determining is the expression foo(A()); is a postfix-expression for a function call.
I'm confusing...
When parsing the following program
#include <iostream>
using namespace std;
typedef int foo;
class A
{
public:
operator int(){
return 42;
}
};
int main()
{
cout << foo(A());
}
the output will be 42 because 3.4.1/3
For purposes of determining (during parsing) whether an expression is
a postfix-expression for a function call, the usual name lookup rules
apply.
that means: to determine if foo is a postfix-expression (e.g. a cast) or a function call, the compiler will first use name lookup and search for it in the global namespace and/or enclosing scopes / base classes (or with fully qualified lookups if available).
Now take this code:
#include <iostream>
using namespace std;
class A
{
public:
friend int foo(A a){ return 55; }
operator int(){
return 42;
}
};
int main()
{
cout << foo(A());
}
The above will output 55 thanks to ADL: foo will be found by searching inside the scopes defined by its potential arguments, i.e. A.
A friend declaration introduces a (possibly not visible) name as you posted (3.3.1/4)
friend declarations (11.3) may introduce a (possibly not visible) name
into an enclosing namespace
that means the following code will not work
#include <iostream>
using namespace std;
class A
{
public:
friend int foo(A a){ return 55; }
operator int(){
return 42;
}
};
int main()
{
cout << ::foo(A()); // Not found
cout << A::foo(A()); // Not found
}
You might want to search for "friend name injection" and/or the Barton-Nackman trick.
Short story: now ordinary lookups can't find friend declarations.
So the code you posted is well-formed because ADL allows it to run as I explained in the previous passages.

A point from the ISO C++ draft (n3290): 3.4.3.2/1 Namespace members

A point from the ISO C++ draft (n3290): 3.4.3.2/1 Namespace members
If the nested-name-specifier of a qualified-id nominates a namespace,
the name specified after the nested-name-specifier is looked up in
the scope of the namespace. If a qualified-id starts with ::, the
name after the :: is looked up in the global namespace. In either
case, the names in a template-argument of a template-id are looked up
in the context in which the entire postfix-expression occurs.
Here can any one explain about the BOLD part .... and from earlier c++03 draft to c++0x draft he added
If a qualified-id starts with ::, the name after the :: is looked up
in the global namespace.
can any one explain with an example program please
::S is a qualified-id.
In the qualified-id ::S::f, S:: is a nested-name-specifier.
In informal terms, a nested-name-specifier is the part of the id that
begins either at the very beginning of a qualified-id or after the initial scope resolution operator (::) if one appears at the very beginning of the id and
ends with the last scope resolution operator in the qualified-id.
Very informally, an id is either a qualified-id or an unqualified-id. If the id is a qualified-id, it is actually composed of two parts: a nested-name specifier followed by an unqualified-id.
Given:
struct A {
struct B {
void F();
};
};
A is an unqualified-id.
::A is a qualified-id but has no nested-name-specifier.
A::B is a qualified-id and A:: is a nested-name-specifier.
::A::B is a qualified-id and A:: is a nested-name-specifier.
A::B::F is a qualified-id and both B:: and A::B:: are nested-name-specifiers.
::A::B::F is a qualified-id and both B:: and A::B:: are nested-name-specifiers.
Another example:
#include <iostream>
using namespace std;
int count(0); // Used for iteration
class outer {
public:
static int count; // counts the number of outer classes
class inner {
public:
static int count; // counts the number of inner classes
};
};
int outer::count(42); // assume there are 42 outer classes
int outer::inner::count(32768); // assume there are 2^15 inner classes
// getting the hang of it?
int main() {
// how do we access these numbers?
//
// using "count = ?" is quite ambiguous since we don't explicitly know which
// count we are referring to.
//
// Nested name specifiers help us out here
cout << ::count << endl; // The iterator value
cout << outer::count << endl; // the number of outer classes instantiated
cout << outer::inner::count << endl; // the number of inner classes instantiated
return 0;
}
EDIT:
In response to your comment, I believe that statement simply means that the arguments of a template are handled w.r.t the context and line by which they are declared. For example,
in f.~foo();, foo is looked up within f., and within the scope of foo<int>, it is valid to refer to it just with with foo.
It is called as Qualified name lookup.
The leading :: refers the global namespace. Any qualified identifier starting with a :: will always refer to some identifier in the global namespace over the same named identifier in local namespace.
namespace A
{
namespace B
{
void doSomething();
}
}
namespace Z
{
namespace A
{
namespace B
{
void doSomething();
}
}
using namespace A::B // no leading :: refers to local namespace layer
void doSomethingMore()
{
doSomething(); // calls Z::A::B::doSomething();
}
}
namespace Z
{
namespace A
{
namespace B
{
void doSomething();
}
}
using namespace ::A::B // leading :: refers to global namespace A
void doSomethingMore()
{
doSomething(); // calls ::A::B::doSomething();
}
}
The bolded text refers to two different situations. The first part is the distinction of using or not using :: as a prefix. When a qualified name starts with :: the exact namespace is checked starting from the empty namespace, while if it is not present, the search will consider nested namespaces:
namespace A {
void f() { std::cout << "::A::f" << std::endl; }
}
namespace B {
namespace A {
void f() { std::cout << "::B::A::f" << std::endl; }
}
void g() {
A::f(); // ::B::A::f
::A::f(); // ::A::f
}
}
The last sentence in the paragraph refers to the specific of template arguments, and it tells you that the lookup will not start in the namespace that the template was declared, but rather in the namespace where it is being instantiated:
struct A {
static void f() { std::cout << "::A::f()" << std::endl; }
};
template <typename T>
void f() {
T::f();
}
namespace N {
struct A {
static void f() { std::cout << "::N::A::f()" << std::endl; }
};
void g() {
f<A>();
}
}
If lookup started in the template namespace, the call f<A>() would refer to f<::A>, but that clause in the standard states the lookup will start inside namespace N (where the entire postfix-expression occurs), and will thus call ::N::A::f().
int a(1);
class someCls {
private:
int a;
public:
// Assigns this->a with the value of the global variable ::a.
void assignFromGlobal() {
a = ::a;
}
};

C++ ADL in nested namespaces with template function

I have a question regarding the standard ADL resolution in C++.
Here is a sample code explaining my enquiry:
#include <string>
// The mechanism:
namespace A {
template< class C >
::std::string scope(const C*)
{ return "A"; }
namespace B {
template< class C >
::std::string scope(const C *foo)
{ return A::scope(foo)+"::B"; }
} // namespace B
} // namespace A
::std::string scope(...)
{ return ""; }
// The test classes
struct foo {};
namespace A {
struct foo {};
namespace B {
struct foo {};
}
}
// The usage
int main()
{
foo *Foo=0;
A::foo *FooA=0;
A::B::foo *FooB=0;
scope(Foo); // OK, returns ""
scope(FooA); // OK, returns "A"
scope(FooB); // On one compiler, OK returns "A::B" ; On another, compiler error "Ambiguous call" between A::scope() and A::B::scope()
}
So, my question is what is the standard regarding ADL?
Should all the functions from parent namespaces of the argument be found, or only the functions available in the (nested) namespace of the argument + the global functions?
This program has been tested on MSVC 2008 (and compiles with SP but not without...)
According to the standard, ADL works (modulo a couple of special rules)
"as if" the function name were preceded by the namespace; in your last
line, lookup should precede as if you'd written A::B::scope. Which
does not look in the surrounding namespaces.
Note that even within namespace A::B, there would be no ambiguity; in
A::B, A::B::scope hides A::scope. Unqualified name lookup stops
in the scope where it first finds the name.