The following code which doesn't compile under clang but does under gcc and VS:
template<typename T> class bar;
namespace NS
{
template<typename T>
class foo
{
foo() {}
template<typename U> friend class bar;
};
}
template<typename R>
class bar
{
public:
bar()
{
NS::foo<int> f;
}
};
int main(int, char **)
{
bar<int> b;
return 0;
}
It fails with:
main.cpp:20:22: error: calling a private constructor of class 'NS::foo<int>'
NS::foo<int> f;
^
main.cpp:8:9: note: implicitly declared private here
foo() {}
^
bar
should have access to foo
's private constructor but it looks like it doesn't. If I remove namespace NS
, it compiles.
Code looks fine to me, but maybe I'm misunderstanding the C++ standard. Which compiler is correct?
Changing the code to
compiles with clang. The problem seems to be the namespace lookup. The code
actually declared the class NS::bar a friend of NS::foo, so foo should not have been affected. My guess would be that clang is standard conformant and the code should not compile.
I believe that clang is correct. According to [namespace.memdef]/3:
In your case, the name wouldn't appear to be "first declared" by the
friend
declaration. Later in that paragraph, however, emphasis mine:That is, this declaration:
will not look for
bar
outside ofnamespace NS
, so it will not find your earlier declaration. As such, it declares a class templateNS::bar<typename >
to be afriend
offoo
. You will have to qualify the namebar
in order for it to be found:This seems related to GCC Bug 37804.
From cppreference:
It's not the standard, but it is in general correct. So clang seems to be right.