How to befriend a templated class's constructor? - c++

Why does
class A;
template<typename T> class B
{
private:
A* a;
public:
B();
};
class A : public B<int>
{
private:
friend B<int>::B<int>();
int x;
};
template<typename T>
B<T>::B()
{
a = new A;
a->x = 5;
}
int main() { return 0; }
result in
../src/main.cpp:15: error: invalid use of constructor as a template
../src/main.cpp:15: note: use ‘B::B’ instead of ‘B::class B’ to name the constructor in a qualified name
yet changing friend B<int>::B<int>() to friend B<int>::B() results in
../src/main.cpp:15: error: no ‘void B::B()’ member function declared in class ‘B’
while removing the template completely
class A;
class B
{
private:
A* a;
public:
B();
};
class A : public B
{
private:
friend B::B();
int x;
};
B::B()
{
a = new A;
a->x = 5;
}
int main() { return 0; }
compiles and executes just fine -- despite my IDE saying friend B::B() is invalid syntax?

Per the resolution to CWG defect 147 (the resolution was incorporated into C++03), the correct way to name a nontemplate constructor of a class template specialization is:
B<int>::B();
and not
B<int>::B<int>();
If the latter were allowed, there is an ambiguity when you have a constructor template specialization of a class template specialization: would the second <int> be for the class template or the constructor template? (see the defect report linked above for further information about that)
So, the correct way to declare the constructor of a class template specialization as a friend is:
friend B<int>::B();
Comeau 4.3.10.1 and Intel C++ 11.1 both accept that form. Neither Visual C++ 2008 nor Visual C++ 2010 accept that form, but both accept the (incorrect) form friend B<int>::B<int>(); (I will file a defect report on Microsoft Connect).
gcc does not accept either form prior to version 4.5. Bug 5023 was reported against gcc 3.0.2, but the requested resolution in the bug report was the invalid form. It appears the resolution to bug 9050 also resolves this issue and gcc 4.5 accepts the correct form. Georg Fritzsche verified this in a comment to the question.

And the reason your IDE shows friend B::B() as invalid syntax in the latter case? An IDE error.
A workaround I found in gcc for the template case if you can't upgrade is to move the implementation of B() to a member function, void B::init(), and grant friendship to that instead. I'll bet this shuts up your IDE too.
Even if you get this to compile, though, you'll run into the stack overflow problem as soon as you try to instantiate a B.

Doesn't a typedef help? e.g.
class A : public B<int>
{
typedef B<int> Base;
friend Base::Base();
int x;
};
EDIT: The Final Committee Draft for C++0x includes the following language in section 3.4.3.1 [class.qual]:
In a lookup in which the constructor is an acceptable lookup result and the nested-name-specifier nominates a class C: if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C (Clause 9), or if the name specified after the nested-name-specifier is the same as the identifier or the simple-template-id’s template-name in the last component of the nested-name-specifier, the name is instead considered to name the constructor of class C.
Sounds like the name (Base) specified after the nested-name-specifier (Base::) is the same as the identifier in the last component of the nested-name-specifier, so this code does name a constructor.
But I can't reconcile this with section 12.1 [class.ctor]:
Because constructors do not have names, they are never found during name lookup
Oh really? How's that language in 3.4.3.1 work again?
A typedef-name shall not be used as the class-name in the declarator-id for a constructor declaration.
This seems pretty clear, except that section 12.1 appears to discuss only the introducing declaration of a constructor as paragraph 1 excludes the nested-name-specifier, friend, and using. If it does apply to friend declarations, it also appears to forbid friend Base::B();
A special declarator syntax using an optional sequence of function-specifiers (7.1.2) followed by the constructor’s class name followed by a parameter list is used to declare or define the constructor.
Those function-specifiers are inline, virtual, explicit, and constructors can't be virtual anyway.

My guess you;re way into quirks territory here with friend templated constructors. This compiles and runs fine on VS2010 but it produces a stack overflow when default constructor of A calls the default constructor of B which then instantiates A again.

Related

Neither clang nor g++ compile the snippet below. Why? [duplicate]

From [class.access]/7 we have the following sentence:
Similarly, the use of A::B as a base-specifier is well-formed
because D is derived from A, so checking of base-specifiers must
be deferred until the entire base-specifier-list has been seen.
class A {
protected:
struct B { };
};
struct D: A::B, A { };
See live example with clang. As a matter of fact, clang also complains about this snippet, where no deferment is necessary.
class A {
protected:
struct B { };
};
struct D: A, A::B { };
Why does this code not compile?
PS: gcc and VS21013 don't compile the codes either.
This is simply a compiler bug. The normative text of the standard supports the example. The fact that multiple compilers have the same bug means this is part of the standard is tricky to get right.
There are open bugs about this for GCC
and for clang. Note that a few related cases are actually subtle differences between C++03 and C++11, but as far as I can tell, not this one.
[class.access]/1.2 merely states
protected; that is, its name can be used only by members and friends of the class in which it is declared, by classes derived from that class, and by their friends (see 11.4).
and 11.4 does not expand on this. You are using the name B in a class D derived from that class A. That's fine.
I believe this to be a bug with clang. Ideone doesn't accept the code either: http://ideone.com/uiFl9L:
class A {
protected:
struct B { };
};
struct D: A::B, A { };
I checked with gcc-5.1.0, gcc-4.9 and clang-3.7(rc2). The standard explicitly states this as well-formed (see question) thus the compilers are at fault.
The example clearifies [class.access]/6:
All access controls in Clause 11 affect the ability to access a class member name from the declaration of a
particular entity, including parts of the declaration preceding the name of the entity being declared ...
This means, according to [class.access]/2 that a class has access to all base-classes, even before they are declared.

Using decltype to define static members (Intellisense disagrees)

I came up with the idea of using decltype to define static members in a .cpp file, and then using this macro:
#define DEFINE_SYMBOL(x) decltype(x) x
This way, for instance, if class Foo declares static int bar, I can do the following in foo.cpp:
DEFINE_SYMBOL(Foo::bar) = 1337;
This seems a bit "hacky", but it has the advantage of being resilient to changes in the original symbol type. For instance, if bar changes to unsigned in foo.hpp, I wouldn't need to change foo.cpp. It's also easier to read when the type of the member is complex.
However, if the static member is private, in Visual Studio 2015, Intellisense complains about using decltype (saying it's inaccessible). The complaint makes sense, although the program compiles just fine. Now, my question is, is Intellisense wrong, or is this usage of decltype not recommended (and why)?
Intellisense is incorrect, both gcc and clang compile a similar program and we can see the draft C++ standard section 11 [class.access] says:
All access controls in Clause 11 affect the ability to access a class member name from the declaration of a particular entity, including parts of the declaration preceding the name of the entity being declared and, if the
entity is a class, the definitions of members of the class appearing outside the class’s member-specification.
[ Note: this access also applies to implicit references to constructors, conversion functions, and destructors.
—end note ] [ Example:
class A {
typedef int I; // private member
I f();
friend I g(I);
static I x;
template<int> struct Q;
template<int> friend struct R;
protected:
struct B { };
};
A::I A::f() { return 0; }
A::I g(A::I p = A::x);
A::I g(A::I p) { return 0; }
A::I A::x = 0;
template<A::I> struct A::Q { };
template<A::I> struct R { };
struct D: A::B, A { };
Here, all the uses of A::I are well-formed because A::f, A::x, and A::Q are members of class A and g and
R are friends of class A. This implies, for example, that access checking on the first use of A::I must be
deferred until it is determined that this use of A::I is as the return type of a member of class A. Similarly,
the use of A::B as a base-specifier is well-formed because D is derived from A, so checking of base-specifiers
must be deferred until the entire base-specifier-list has been seen. —end example ]

Maybe my understanding of [class.access]/7 isn't correct, but

From [class.access]/7 we have the following sentence:
Similarly, the use of A::B as a base-specifier is well-formed
because D is derived from A, so checking of base-specifiers must
be deferred until the entire base-specifier-list has been seen.
class A {
protected:
struct B { };
};
struct D: A::B, A { };
See live example with clang. As a matter of fact, clang also complains about this snippet, where no deferment is necessary.
class A {
protected:
struct B { };
};
struct D: A, A::B { };
Why does this code not compile?
PS: gcc and VS21013 don't compile the codes either.
This is simply a compiler bug. The normative text of the standard supports the example. The fact that multiple compilers have the same bug means this is part of the standard is tricky to get right.
There are open bugs about this for GCC
and for clang. Note that a few related cases are actually subtle differences between C++03 and C++11, but as far as I can tell, not this one.
[class.access]/1.2 merely states
protected; that is, its name can be used only by members and friends of the class in which it is declared, by classes derived from that class, and by their friends (see 11.4).
and 11.4 does not expand on this. You are using the name B in a class D derived from that class A. That's fine.
I believe this to be a bug with clang. Ideone doesn't accept the code either: http://ideone.com/uiFl9L:
class A {
protected:
struct B { };
};
struct D: A::B, A { };
I checked with gcc-5.1.0, gcc-4.9 and clang-3.7(rc2). The standard explicitly states this as well-formed (see question) thus the compilers are at fault.
The example clearifies [class.access]/6:
All access controls in Clause 11 affect the ability to access a class member name from the declaration of a
particular entity, including parts of the declaration preceding the name of the entity being declared ...
This means, according to [class.access]/2 that a class has access to all base-classes, even before they are declared.

Is it legal to friend a function via a using declaration?

The following (LiveWorkspace here) is rejected by GCC 4.7.2, GCC 4.8.0, and ICC 13.0.1.
namespace A {
namespace B {
void C();
}
using B::C;
}
class D {
friend void A::C();
};
Additionally, it crashes Clang 3.2 (!). I've submitted a bug report and patch already, for the crash bug, but I'm not 100% sure if this code is really in error, because I can't find anything in §7.3.3 [namespace.udecl] or §11.3 [class.friend] that explicitly addresses this case, but maybe there's something in the definition of one of the various name specifier terms that I've missed.
Furthermore, it seems like all four compilers accept the following (LiveWorkspace here):
namespace A {
namespace B {
class C;
}
using B::C;
}
class D {
friend class A::C;
};
There doesn't seem to be anything fundamentally different about these two cases, so I'm curious what GCC and ICC's grounds to reject the first example but not this one are, if any. Can anyone more familiar with the standard find anything that addresses this?
It's definitely a minor issue at best, but since I'm patching it, I'd like to be sure I'm doing the right thing...
EDIT: This is patched now in clang/trunk!
NEW EDIT: Johannes's answer below explains why my original example is rejected, but it doesn't seem to explain why GCC and ICC also reject the following (LiveWorkspace here):
namespace A {
namespace B {
void C();
}
using B::C;
class D {
friend void C();
};
}
8.3p1:
When the declarator-id is qualified,
the declaration shall refer to a previously declared member of the class or namespace to which the qualifier
refers (or, in the case of a namespace, of an element of the inline namespace set of that namespace (7.3.1))
or to a specialization thereof; the member shall not merely have been introduced by a using-declaration
in the scope of the class or namespace nominated by the nested-name-specifier of the declarator-id.
A class foo; or class foo::bar; does not contain a declarator-id, so it is not affected by this rule. Instead, the foo::bar is part of an elaborated-type-specifier (7.1.6.3).

Obviously ambiguous call does not cause a compilation error on GCC

I was surprised by the fact that GCC does not consider the call to foo() in the following program ambiguous:
#include <iostream>
struct B1 { bool foo(bool) { return true; } };
struct B2 { bool foo(bool) { return false; } };
struct C : public B1, public B2
{
using B1::foo;
using B2::foo;
};
int main()
{
C c;
// Compiles and prints `true` on GCC 4.7.2 and GCC 4.8.0 (beta);
// does not compile on Clang 3.2 and ICC 13.0.1;
std::cout << std::boolalpha << c.foo(true);
}
The above function call compiles and returns true on GCC 4.7.2 and GCC 4.8.0 (beta), while it won't compile (as I would expect) on Clang 3.2 and ICC 13.0.1.
Is this a case of "no diagnostic required", or is it a bug in GCC? References to the C++11 Standard are encouraged.
§7.3.3/3:
In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the class being defined. If such a using-declaration names a constructor, the nested-name-specifier shall name a direct base class of the class being defined; otherwise it introduces the set of declarations found by member name lookup (10.2, 3.4.3.1).
¶14:
… [ Note: Two using-declarations may introduce functions with the same name and the same parameter types. If, for a call to an unqualified function name, function overload resolution selects the functions introduced by such using-declarations, the function call is ill-formed.
¶16:
For the purpose of overload resolution, the functions which are introduced by a using-declaration into a
derived class will be treated as though they were members of the derived class.
So, the using declarations are legal, but the functions are peers in the same overload set, as you said, and the program is ill-formed.
The call to foo(true) in your program is, as you say, clearly ambiguous; furthermore, it is ambiguous according to the algorithm presented in §10.2 and consequently, it should be flagged on use. (Flagging the using declaration would be incorrect; 10.2(1) clearly states that ambiguous uses of names are flagged on lookup, not on declaration.)
It's interesting to contrast this program with a similar one, which is the subject of a a recognized gcc bug (slightly modified from that bug report to make the parallel clearer):
#include <iostream>
struct A {
static int foo() {return 1;}
static int foo(char) { return 2;}
};
struct B1 : A {
// using A::foo;
};
struct B2 : A {
// using A::foo;
};
struct C : B1, B2 {
// using B1::foo;
// using B2::foo;
};
int main()
{
std::cout << C::foo();
}
The above program is correct; despite the diamond inheritance, foo is a static member of A, so it is not ambiguous. In fact, gcc compiles it without trouble. However, uncommenting the two instances of using A::foo, which does not change anything about either foo, causes gcc to produce the oddly reduplicated error noted in the bug report. Uncommenting the two using declarations inside C, which presumably triggers the other bug which is the subject of this question, then masks the static function bug and causes the program to compile again.
clang seems to handle all possible variants of this program, for what it's worth.
Finally, note that an explicitly declared foo(bool) within C (in the original program) will win out over any foo(bool) brought into C's scope by using declarations. I suspect that both of these bugs are the result of bad bookkeeping while trying to keep track of the various function declarations in each class's scope and their individual provenance (as a sequence of using declarations and function declarations).