ADL inhibited if the name of the function is enclosed in parenthesis??

Hi,

I found this phrase which I don't understand and it's about ADL lookup:

<comment>
ADL inhibited if the name of the function is enclosed in parenthesis
</comment>

Any explanations or examples?

I tried this code to see but Visual Studio 2017 does not care about this parenthesis:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using namespace std;

namespace N
{
	struct S
	{
		int i;
	};
	void f(S s)
	{
		cout << s.i << endl;
	}
	void g(S s)
	{
		cout << s.i << endl;
	}
	void h(int i)
	{
		cout << i << endl;
	}
}

struct Base
{
	void f(N::S s)
	{

	}
};

struct D : Base
{
	void mf(N::S s)
	{

	}

	void g(N::S s)
	{
		(f)(s);   /// this should fail but it does not!
		mf(s);
	}
};


Regards,
Juan
That's a member function call, because the expression (f) names the member function Base::f, which is visible without ADL.

To see the behavior referenced in the comment above, get rid of Base::f.
Last edited on
Got it mbozzi. Thanks.
Now, why does this happen? Why does placing the function inside parenthesis changes the lookup rules?

Regards,
Juan
Because ADL applies only when the function name is an unqualified-id.

An unqualified-id is basically an unqualified name - i.e., a name without the scope operator applied. It may appear on the right of a member-access expression (e.g., bar in foo.bar). No unqualified-id is parenthesized. Specifically, its grammar may be found here:
http://nongnu.org/hcb/#unqualified-id

The standard (draft) has more specific wording:
[basic.lookup.argdep]
When the postfix-expression in a function call is an unqualified-id, other namespaces not considered during the usual unqualified lookup may be searched [...]

A postfix expression in a function call is the expression that names the thing used as a function.

See: http://eel.is/c++draft/basic.lookup.argdep#1
Last edited on
why would we want to parenthesize a function name?
I don't know, and I don't recall ever seeing this "feature" used. Maybe someone else has an example?

If the programmer intended to disable ADL, a more reasonable suggestion is to simply make the function name a qualified-id instead, i.e., to use the full name, as in namespace::function(args).

Some notes on potential problems with ADL:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1893.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3490.html
Last edited on
> why would we want to parenthesize a function name?

Typically used to prevent macro expansion when the name of a function has been masked by a masking-macro.
(This is more often seen in C code)

For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <cstdlib>
#include <map>
#include <cassert>

namespace debug
{
    extern std::map< void*, std::tuple<const char*, int, std::size_t> > allocs ;
    void* traced_malloc( std::size_t sz, const char* file, int line )
    {
        void* const p = (malloc)(sz) ;
        allocs[p] = { file, line, sz } ;
        std::clog << file << " : " << line << " malloc " << sz << " bytes at " << p << '\n' ;
        return p ;
    }

    void traced_free( void* p, const char* file, int line )
    {
        std::clog << file << " : " << line << " free memory at " << p << '\n' ;
        assert( allocs.erase(p) == 1 ) ;
        free(p) ;
    }

    void dump_allocs()
    {
        for( const auto& pair : allocs )
        {
            auto [file,line,sz] = pair.second ;
            std::cout << "block at " << pair.first << " size: " << sz
                      << " bytes allocated from: " << file << " : " << line << '\n' ;
        }
    }
}

#define malloc(sz) debug::traced_malloc( sz, __FILE__, __LINE__ )
#define free(p) debug::traced_free( p, __FILE__, __LINE__ )

int main()
{
    auto p = malloc(100) ; // debug::traced_malloc
    free(p) ; // debug::traced_free

    malloc(200) ; // debug::traced_malloc

    p = (malloc)(300) ; // ::malloc
    (free)(p) ; // ::free

    (malloc)(400) ; // ::malloc

    std::cout << "\nun-freed blocks:\n" ;
    debug::dump_allocs() ;
}

std::map< void*, std::tuple<const char*, int, std::size_t> > debug::allocs ;

http://coliru.stacked-crooked.com/a/f54463e3b70b682e
That's it!! As usual JLBorges comes with the right answer!

Thanks!!
Juan
Last edited on
Topic archived. No new replies allowed.