There are 3 examples:
I.
typedef int foo;
namespace B
{
struct S
{
operator int(){ return 24; }
};
int foo(B::S s){ return 0; }
}
int main()
{
int t=foo(B::S()); //24, ADL does not apply
}
II.
namespace B
{
struct S
{
operator int(){ return 24; }
};
int foo(B::S s){ return 0; }
}
int main()
{
int t=foo(B::S()); //0, ADL applies
}
III.
namespace B
{
struct S
{
operator int(){ return 24; }
};
int foo(B::S s){ return 0; }
}
int foo(B::S s){ return 12; }
int main()
{
int t=foo(B::S()); //error: call of overloaded ‘foo(B::S)’ is ambiguous
//ADL applies
}
It is not clear for me what is the actual conditions to ADL lookup will be apply? I need in reference to standard described it.
This Standard paragraph clarifies, and even has an example very much like your first example.
3.4.1/3:
The lookup for an unqualified name used as the postfix-expression of a function call is described in 3.4.2 [basic.lookup.argdep]. [Note: For purposes of determining (during parsing) whether an expression is a postfix-expression for a function call, the usual name lookup rules apply. The rules in 3.4.2 have no effect on the syntactic interpretation of an expression. For example,
typedef int f;
namespace N {
struct A {
friend void f(A &);
operator int();
void g(A a) {
int i = f(a); // f is the typedef, not the friend
// function: equivalent to int(a)
}
};
}
Because the expression is not a function call, the argument-dependent name lookup (3.4.2) does not apply and the friend function f is not found. -end note]
Your first example does not illustrate ADL. In the line
int t=foo(B::S());
foo is typedefed to int.
The following code has some better illustrations of ADL.
#include <iostream>
namespace B
{
struct S
{
operator int(){ return 24; }
};
int foo(S s){ return 100; }
int bar(S s){ return 400; }
}
namespace C
{
struct S
{
operator int(){ return 24; }
};
int foo(S s){ return 200; }
}
int bar(C::S s){ return 800; }
int main()
{
// ADL makes it possible for foo to be resolved to B::foo
std::cout << foo(B::S()) << std::endl;
// ADL makes it possible for foo to be resolved to C::foo
std::cout << foo(C::S()) << std::endl;
// ADL makes it possible for bar to be resolved to B::bar
std::cout << bar(B::S()) << std::endl;
// ADL makes it possible for bar to be resolved to ::bar
std::cout << bar(C::S()) << std::endl;
}
Related
In the following snippet, the function B::f() is a "wrapper" around the function A::f(). But I assume that A::f() return type is an "opaque" type which I don't know if it has a value or reference semantics. So I cannot use auto or const auto & as return type for B::f(). I thought that auto && would do the trick, but it does not as auto && is deduced as A::OpaqueType &... Is it possible here to avoid writing A::OpaqueType?
#include <iostream>
struct A {
using OpaqueType=int; // But it could have been `const int &`
OpaqueType f() const {
return i;
}
int i=42;
};
struct B {
// how could I use `auto` here to avoid writing the `A::OpaqueType`?
// I would have expected that `auto &&` would do the trick but it does not
A::OpaqueType f() const {
return a.f();
}
A a;
};
int main()
{
B b;
std::cout << b.f() << std::endl;
}
The following snippet confuses me, as I would have expected that the return type of f() and g() would be int, but it is int & for f() and int && for g() (I don't even understand why it is not the same)... How this can be explained?
#include <iostream>
auto &&f() {
int i=42;
return i;
}
struct A {
int f() {return i;}
int i=42;
};
auto &&g() {
A a;
return a.f();
}
int main()
{
if (std::is_same_v<decltype(f()), int &>) {
std::cout << "f() return type is 'int &'\n";
}
if (std::is_same_v<decltype(g()), int &&>) {
std::cout << "g() return type is 'int &&'\n";
}
}
Thanks!
Pretty sure what you are looking for is decltype(auto). This will return by value if the expression in the return statement returns by value, and it will return by reference if the expression in the return statement returns by reference. That would give you
decltype(auto) f() const {
return a.f();
}
Came across the following example:
https://godbolt.org/g/yYgZox
#include <iostream>
struct A {
operator void* (){ return nullptr; }
};
A a;
A& getA () {
return a;
}
int main(int, char**)
{
int x = 0;
// this works
if (std::cout << x) {
return 1;
}
// this works only because we have operator void* defined
if (getA()) {
return 2;
}
return 0;
}
Why it is OK for the compiler to cast a reference to void* when such defined as a member function?
I have one question about friend functions/classes. Consider the following code:
#include <iostream>
struct A
{
private:
int a = 5;
friend int foo(A a);
};
int foo(A a)
{
return a.a;
}
int a = foo(A());
int main(){ std::cout << a << std::endl; }
DEMO
It works fine and both int foo() within class scope and global scope refer to the same entity. Although, the declaration of int foo() within the class scope didn't introduce a name into the global scope. If it were then we would recieve a linker-error intstead of compile-error in the code:
#include <iostream>
struct A
{
private:
int a = 5;
friend int foo();
};
int a = foo(); //undeclared foo
int main(){ std::cout << a << std::endl; }
DEMO
I can't find explanation about this in the Standard. What it says is N3797:11.3/6 [class.friend]:
A function can be defined in a friend declaration of a class if and
only if the class is a non-local class (9.8), the function name is
unqualified, and the function has namespace scope.
So, it explains why the following code works fine:
#include <iostream>
struct A
{
private:
int a = 5;
friend int foo(A a)
{
return a.a;
}
};
int a = foo(A());
int main(){ std::cout << a << std::endl; }
DEMO
We defined the function in the friend declaration and, as the Standard said it became the member of the global namespace. But the rule covers the defintion, not declaration. Obviously, that's not any declaration is definition. So we can't apply one to the first example.
In the last program
#include <iostream>
struct A
{
private:
int a = 5;
friend int foo(A a)
{
return a.a;
}
};
int a = foo(A());
int main(){ std::cout << a << std::endl; }
The compiler finds definition of function foo only due to the argument dependent lookup.
You should consider the following section of the C++ Standard
3.4.2 Argument-dependent name lookup
2 For each argument type T in the function call, there is a set of
zero or more associated namespaces and a set of zero or more
associated classes to be considered. The sets of namespaces and
classes is determined entirely by the types of the function
arguments (and the namespace of any template template argument).
Typedef names and using-declarations used to specify the types do not
contribute to this set.
Thus in this program the compiler searches the function in the scope of the class because the argument of the function has the class type. If you will change the function definition for example the following way then the compiler will not find the function.
#include <iostream>
struct A
{
public:
A( int x ) : a( 2 * x ) {}
private:
int a;
friend int foo( int x )
{
A a( x );
return a.a;
}
};
int a = foo( 10 );
int main()
{
std::cout << a << std::endl;
return 0;
}
But if you add a declaration of the function in the scope where the class is defined then the compiler will see the function
#include <iostream>
struct A
{
public:
A( int x ) : a( 2 * x ) {}
private:
int a;
friend int foo( int x )
{
A a( x );
return a.a;
}
};
int foo( int );
int a = foo( 10 );
int main()
{
std::cout << a << std::endl;
return 0;
}
Here the program output is
20
Can one show me an example of ADL without using templates? Never seen something like that. I mean something like here. Specifically I am interested in example in which it leads to some pitfall like in mentioned.
EDIT:
I think Tomalak's answer can be extended to pitfall. Consider this:
namespace dupa {
class A {
};
class B : public A {
public:
int c;
B() {
}
};
void f(B b) {
printf("f from dupa called\n");
}
}
void f(dupa::A) {
printf("f from unnamed namespace called\n");
}
int main()
{
dupa::B b;
f(b);
return 0;
}
Here we expect that f from unnamed namespace will be called, but instead another one is called.
I can't show you something leading to a pitfall, but I can demonstrate ADL working without templates:
namespace foo {
struct T {} lol;
void f(T) {}
}
int main() {
f(foo::lol);
}
Note that lol's type has to be a class-type; I originally tried with a built-in, as you saw, and it didn't work.
The trick to get confusion is creating an scenario where the arguments to the function are interchangeable or convertible and that ADL might pick something that might not be what you would expect. I am not sure if this is impressive or just expected:
namespace a {
struct A {};
void f( A* ) { std::cout << "a::f" << std::endl; }
}
namespace b {
struct B : ::a::A {};
void f( B* ) { std::cout << "b::f" << std::endl; }
}
void test() {
f( new b::B ); // b::f
a::A* p = new b::B;
f( p ); // a::f
}
The types are the same, but ADL will check the static type of the argument and add that namespace into the search. That in turn means that the exact static type might make different functions visible to the compiler. Things can be more confusing when there are more than one argument on which ADL or overload resolution can apply .
No templates.
Using swap() because that is the most common usage.
#include <iostream>
namespace One
{
class A {};
void swap(A& lhs, A& rhs) { std::cout << "Swap-One A\n";}
}
namespace Two
{
class A {};
void swap(A& lhs, A& rhs) { std::cout << "Swap-Two A\n";}
}
int main()
{
One::A oneA_l;
One::A oneA_r;
Two::A twoA_l;
Two::A twoA_r;
swap(oneA_l, oneA_r);
swap(twoA_l, twoA_r);
}
C++ continues to surprise me.
Today i found out about the ->* operator. It is overloadable but i have no idea how to invoke it. I manage to overload it in my class but i have no clue how to call it.
struct B { int a; };
struct A
{
typedef int (A::*a_func)(void);
B *p;
int a,b,c;
A() { a=0; }
A(int bb) { b=b; c=b; }
int operator + (int a) { return 2; }
int operator ->* (a_func a) { return 99; }
int operator ->* (int a) { return 94; }
int operator * (int a) { return 2; }
B* operator -> () { return p; }
int ff() { return 4; }
};
void main()
{
A a;
A*p = &a;
a + 2;
}
edit:
Thanks to the answer. To call the overloaded function i write
void main()
{
A a;
A*p = &a;
a + 2;
a->a;
A::a_func f = &A::ff;
(&a->*f)();
(a->*f); //this
}
Just like .*, ->* is used with pointers to members. There's an entire section on C++ FAQ LITE dedicated to pointers-to-members.
#include <iostream>
struct foo {
void bar(void) { std::cout << "foo::bar" << std::endl; }
void baz(void) { std::cout << "foo::baz" << std::endl; }
};
int main(void) {
foo *obj = new foo;
void (foo::*ptr)(void);
ptr = &foo::bar;
(obj->*ptr)();
ptr = &foo::baz;
(obj->*ptr)();
return 0;
}
The overloaded ->* operator is a binary operator (while .* is not overloadable). It is interpreted as an ordinary binary operator, so in you original case in order to call that operator you have to do something like
A a;
B* p = a->*2; // calls A::operator->*(int)
What you read in the Piotr's answer applies to the built-in operators, not to your overloaded one. What you call in your added example is also the built-in operator, not your overloaded one. In order to call the overloaded operator you have to do what I do in my example above.
Like any other opperator, you can also call it explicitly:
a.operator->*(2);