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).
Related
We know that a 'using declaration' for a namespace's member name in a scope where another entity is defined there with the same name, causes a compile time error: "symbol x is already defined".
The error is detected at the point the 'using declaration' appears not at use point like a 'using directive'.
A using declaration in a class scope allows only exposing a base class member name.
Here is an example:
#include <iostream>
using namespace std;
struct Foo{
Foo(int x) : x_(x){}
int x_ = 0;
};
struct Bar{
Bar(int y) : y_(y){}
int y_ = 0;
};
struct FooBar : Foo, Bar{
using Foo::Foo; // inheriting Foo's ctors
using Bar::Bar; // inheriting Bar's ctors
int x_ = 10;
// using Foo::x_; // error detected here
};
int main(){
FooBar fb(5); // error detected here
}
As you can see above the using declaration for Foo::x_ causes a compile-time error at the point the using appears and it is OK.
But the using declaration for base classes Foo and Bar constructors don't issue an error until the usage in main?!!
Normally FooBar inherits Foo(int); so when using Bar::Bar; appears normally the compiler complains but the code works fine until I try to use that constructor. FooBar(int).
After inheriting all the constructors, the compiler defines a derived class ctor and make it call its base class one passing in its parameters to it so it is as if we wrote:
struct FooBar : Foo, Bar{
FooBar(int x) : Foo(x){}
FooBar(int x) : Bar(x){}
//...
};
So why the compiler allows such bug? and wait until the use of that ctor to flag ambiguity??
It looks to me that a using declaration in such case undergoes the same thing like a using directive.
It is a general (though not universal) principle of C++ that a prefix of a program is valid if and only if there is some valid completion of it that uses the declarations in the prefix. This is why it’s not an error to declare an unused variable: it could be used, and it’s “too late” to reject it later if it’s not. Here, that principle is generalized a bit to say that, because overload resolution can usually distinguish between functions from different namespaces or base classes, there is no check for conflict at all.
Not so for variables, since you can’t possibly use the ambiguous combination. Also not so if one of the conflicting functions declarations is a direct member and a sibling of the using-declaration: in that case, you can’t possibly use the function you declared, so you are presumed not to have meant it.
#include <iostream>
struct A {
void test() { std::cout << "A\n"; }
};
struct B : A {
void test() { std::cout << "B\n"; }
};
struct C : B {
using A::test;
using B::test;
};
int main() {
C().test(); // Is this ambiguous?
return 0;
}
In this example, g++ 8.1.0 compiles successfully and calls test() from B.
clang++ 3.8.0 reports: error: call to member function 'test' is ambiguous.
Which is correct? If it is g++, what is the rule that picks B::test over A::test?
I believe Clang is correct.
According to [namespace.udecl]/13:
Since a using-declaration is a declaration, the restrictions on declarations of the same name in the same declarative region ([basic.scope]) also apply to using-declarations.
Since you can't declare two identical member functions, the same applies to using declarations.
GCC lets it compile and test() call becomes the first declaration. In the example given, it'll call the A::test(). But ISO C++ defines it as ambiguous. Visual Studio and clang won't let you compile it. Additionally, this the VS error message: 'B::test': ambiguous call to overloaded function. In my opinion, GCC is wrong by letting it compile.
Here’s a class with an undefined method. It seems compilers allow instances of this class to be constructed, so long as the undefined member function is never called:
struct A {
void foo();
};
int main() {
A a; // <-- Works in both VC2013 and g++
a.foo(); // <-- Error in both VC2013 and g++
}
Here’s a similar situation, but one that involves inheritance. Subclass Bar extends base class Foo. Foo defines a method g(). Bar declares the same-named method but does not define it:
#include <iostream>
struct Foo {
void g() { std::cout << "g\n"; }
};
struct Bar : Foo {
void g();
};
int main() {
Bar b; // Works in both VC2013 and g++
b.Foo::g(); // Works in both VC2013 and g++
b.g(); // Error in both VC2013 and g++
}
Here's a variation of the above. The only difference here is that g() is virtual to both Foo and Bar:
#include <iostream>
struct Foo {
virtual void g() { std::cout << "g\n"; }
};
struct Bar : Foo {
virtual void g();
};
int main() {
Bar b; // Works in g++. But not in VC2013, which gives
// 'fatal error LNK1120: 1 unresolved externals'
b.Foo::g(); // Works in g++, but VC2013 already failed on b's construction
b.g(); // Error in g++, but VC2013 already failed on b's construction
}
See the code comments for contrast of different behavior between VC2013 and g++.
Which compiler is correct, if any?
Why does VC2013's compiler have some different complaints in its version with the virtual keyword compared to the one in its version without the virtual keyword?
Are unused undefined methods always allowed? If not, what are all the cases in which they're
not allowed?
Does Bar’s declaration of g() count as overriding
even when Bar doesn't provide a definition?
Which compiler is correct, if any?
They are both right. Your code is wrong, no diagnostic required. [class.virtual]/11
A virtual function declared in a class shall be defined, or declared
pure (10.4) in that class, or both; but no diagnostic is required
(3.2).
[intro.compliance]/2:
If a program contains a violation of a rule for which no diagnostic is
required, this International Standard places no requirement on
implementations with respect to that program.
Have a look at your optimization settings for GCC, they may influence the behavior.
Are unused undefined methods always allowed?
A member function must be defined if and only if it is odr-used. [basic.def.odr]/3:
Every program shall contain exactly one definition of every non-inline
function or variable that is odr-used in that program; no diagnostic
required.
Now consider [basic.def.odr]/2:
An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof.
[…]
A virtual member function is odr-used if it is not pure.
A non-overloaded function whose name appears as a potentially-evaluated expression or a member of a set of candidate functions, if selected by overload resolution when referred to from a potentially-evaluated expression, is odr-used, unless it is a pure virtual function and its name is not explicitly qualified.
You are still allowed to use undefined non-virtual member functions inside decltype or sizeof. But non-pure virtual functions are odr-used simply because they are not pure.
Does Bar’s declaration of g() count as overriding even when Bar
doesn't provide a definition?
Yes.
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).
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.