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://www.pickinpatchfarm.com/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://www.pickinpatchfarm.com/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.pickinpatchfarm.com/jtc1/sc22/wg21/docs/papers/2005/n1893.pdf
http://www.pickinpatchfarm.com/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://www.pickinpatchfarm.com/a/f54463e3b70b682e
That's it!! As usual JLBorges comes with the right answer!

Thanks!!
Juan
Last edited on
Registered users can post here. Sign in or register to post.
  • 1007451581 2018-02-22
  • 8908121580 2018-02-22
  • 141161579 2018-02-22
  • 9421578 2018-02-22
  • 2826901577 2018-02-22
  • 3647361576 2018-02-22
  • 5717551575 2018-02-22
  • 523811574 2018-02-22
  • 6439871573 2018-02-22
  • 8109431572 2018-02-22
  • 8757321571 2018-02-22
  • 5265111570 2018-02-22
  • 3351351569 2018-02-22
  • 5109361568 2018-02-22
  • 4455391567 2018-02-22
  • 9091121566 2018-02-22
  • 24791565 2018-02-22
  • 2486841564 2018-02-21
  • 9847231563 2018-02-21
  • 9264681562 2018-02-21