difference in static vs anonymous namespace for second pass name lookup during template instantiation

Viewed 45

I've long since stopped using static for helper functions in favor of an anonymous namespace, which has the advantage of working with types, variables, and templates as well as for functions.

However, I was surprised when a function was not found when I replaced a call to it with a wrapper template. See code at https://godbolt.org/z/GrojceqGx with compiler and options that match my project.

#include <utility>
//#define WORKING

class C {};

template <typename Left, typename Right>
auto wrapper (Left&& left, Right&& right, const char* name)
{
    return foo (std::forward<Left>(left),std::forward<Right>(right));
}

#ifdef WORKING
static
void foo (C& left, int right)
{
    // compiles when using static function
}
#else
namespace {
void foo (C& left, int right)
{
    // fails to compile in anonymous namespace
}
}
#endif

void sample()
{
    C x;
    wrapper (x, 17, "call 1");
}

Why does the instantiation of wrapper see foo when it is static but not when it is in an anonymous namespace? The point of instantiation is in this translation unit, in the same spot either way.

1 Answers

Because the anonymous namespace is, believe it or not, another namespace entirely. And not the global namespace.

foo is found by ADL when you use static. Because now foo is properly in the associated namespace of C (the global namespace).

It will work however for an inline anonymous namespace, i.e.

inline namespace { }

Since ADL is designed to work nice with inline namespaces.

Related