I have code like this:
class A{
public:
int b;
};
int main()
{
A a{.b = 5};
}
And the program compiles.
However, when I add another class and I make A inherit that class (like below), it throws an error "no matching function for call to ‘A::A()’" (or "No matching constructor for initialization of A").
class C{
};
class A: public C{
public:
int b;
};
int main()
{
A a{.b = 5};
}
Why?
You are using feature "Designated initializers" which is available since C++20.
Also I can't reproduce this issue: https://godbolt.org/z/fz3PeP
note with C++17 gcc and clang just file an warning, msvc file an error
with C++20 it is fine on all three (msvc needs c++latest option).
with C++14 it files error everywhere
So looks like problem is just compiler version or configuration
Related
I'm writing some code using pimpl idiom with unique_ptr. When I tried to use in-class initialization to set unique_ptr to nullptr by default, gcc gave a compile error, while clang and msvc both successfully compiled the code. And if I didn't use in-class initialization the error went away.
// A.h
#pragma once
#include <memory>
using namespace std;
class B;
class A
{
private:
////////////////////////
// here gives the error!
////////////////////////
unique_ptr<B> impl{nullptr}; // error only with gcc,
// ok with clang and msvc
unique_ptr<B> impl2; // ok with all three
public:
A();
~A();
};
// A.cpp
#include "A.h"
class B
{
private:
int b{5};
public:
B() = default;
~B() = default;
};
A::A() = default;
A::~A() = default;
// main.cpp
#include "A.h"
int main()
{
A a;
return 0;
}
When I compiled the above code, gcc complained "error: invalid application of ‘sizeof’ to incomplete type ‘B’". I've tried both gcc 8.3 and gcc 9.1 with no success. Is this a compiler bug? Thanks!
Edit:
I tried as #eerorika suggested. If the header and source files are merged into one single file, it can compile normally, but not separated.
Edit
Confirmed to be compiler bug and already fixed in gcc9.2.
The program, and the default member initialiser in particular, is well-formed. If a compiler refuses to compile, then it is a bug in the compiler as far as I can tell.
I can reproduce the problem with GCC 9.1 but not 9.2 nor trunk, so it appears to have been fixed. With older versions, you may need to give up using the default member initialiser as a workaround.
#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.
I am facing a compilation error with one gcc version (4.3.2), whereas the same code will be compiled without complaints with a newer version of gcc, e.g. 4.5.2.
The following example illustrates the problem:
class Base {
protected:
int member;
};
template<typename T>
class A : public Base {
};
template<typename T>
class C : public A<T> {
C() {
Base::member = 1;
}
};
int main() {
}
For 4.3.2 I am getting:
test.cpp: In constructor 'C<T>::C()':
test.cpp:4: error: object missing in reference to 'Base::member'
test.cpp:14: error: from this location
For 4.5.2 it compiles just fine.
If one compiler version accepts the code it cannot be completely wrong. My guess is that it conforms to the C++ standard, but the older compiler was lacking a proper implementation of the same.
What exactly is the problem?
Is there a portable way of writing that kind of code such that as much compilers as possible accept it?
This is definitely a bug in the earlier version of g++ but the solution is simple: Just add this-> to the expression, as this->Base::member = 1; which unconfuses the compiler.
The following C++11 code compiles successfully on my GCC 4.8:
struct NonStack
{
private:
NonStack() = default;
public:
static NonStack* Create(){
return new NonStack;
}
};
NonStack a;
int main() { }
However the following gives a compilation error:
struct NonStack
{
private:
NonStack(){}
};
NonStack a;
int main() { }
Why does the first one succeed? Shouldn't the private defaulted constructor prohibit creation of an object via NonStack a;?
This is gcc bug 54812, the compiler fails to respect access specifiers for explicitly defaulted special member functions. Bug 56429, which is marked as a duplicate of the earlier one, has a test case that is almost identical to the example in the question.
The solutions are to upgrade to gcc4.9, which resolves the issue. Or create an empty body for the constructor, instead of explicitly defaulting it, as you've done in the second example.
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).