error: base class 'A1' has private copy constructor - c++

Using Clang 3.7 on windows platform
See following code:
class A1
{
public:
A1(char* name){}
virtual ~A1() {}
private:
A1(const A1&) {}
};
class B1 : public A1
{
public:
B1(): A1(""){}
};
I get the following error:
MyFile(31): 8: error: base class 'A1' has private copy constructor
B1(): A1(""){}
^
MyFile(25): 2: note: declared private here
A1(const A1&) {}
^
Making A1 copy constructor public, eliminates the error!
What happened here?
Note: that by changing (as I should)
A1(const char* name)
I get no errors and all compile as expected

I imagine that this is just an artefact of how the diagnostics are generated.
First, lookup attempts to find a constructor to match your "call" (it's not a call but whatever)
The ctor taking char* doesn't match, as you know
The only other candidate is private
The compiler tries to see whether it can instantiate a temporary A1 from your "" argument to make that work
In doing so, again all it can find is private constructors
The compiler decides to complain about that before doing anything else
One might argue that this is a quality of implementation issue.
Amusingly, GCC 6.1.0 (even in pedantic C++14 mode) compiles your code as originally written, spitting out only a warning for the broken literal conversion.

You cannot call the constructor A1(char* name) using a string literal, becase a string literal is not convertible to char* (such deprecated conversion did exist prior to c++11). Or rather, a program that does call the constructor is ill-formed, and the implementation is allowed to refuse to compile.
As such, the overload resolution looks for other alternatives. The only other potential alternative that has the same number of arguments, is the copy constructor.
For whatever reason, clang appears to prefer the implicit conversion from string literal, to A1, thereby creating a temporary, that could be used for copy-initialization, over using the direct construction from the literal. This behaviour leads to the confusing compilation error.
Both alternatives are ill-formed, and clang appropriately warns about it: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings]. The program does compile, if you set the standard mode to older than c++11 (in which case the program would be well-formed, even though it does use a deprecated conversion). Interestingly, if we disallow the conversion, then the program compiles even in the current standard mode:
class A1
{
public:
explicit A1(char* name){} // note the explicit
virtual ~A1() {}
private:
A1(const A1&) {}
};
G++ behaves differently and your program compiles fine (with the appropriate warning of course). Both compilers appear to comply to the standard in this regard.
Moral of the story: Always read the warnings as well. In this case, the warning was perfectly clear, and easy to solve, while the same bug indirectly caused an error that was not helpful in the solving of the bug.

Related

Encounter the error: defaulted definition of default constructor is not constexpr when compile with clang-cl

I'm trying to compile these code with clang-cl with LLVM 15.
class Foo
{
public:
constexpr Foo() = default;
private:
int i;
};
int main(void)
{
Foo f;
}
The compilation command line is:
\> bazel build ... --compiler=clang-cl
The error will be displayed
cpp-constexpr/main.cpp(4,5): error: defaulted definition of default constructor is not constexpr
constexpr Foo() = default;
^
cpp-constexpr/main.cpp(13,9): error: no matching constructor for initialization of 'Foo'
Foo f;
^
cpp-constexpr/main.cpp(6,5): note: candidate constructor not viable: requires 1 argument, but 0 were provided
Foo(const Foo&) = delete;
^
2 errors generated.
Target //cpp-constexpr:constexpr failed to build
If it is compiled with MSVC 2022/2019, there will be no error at all. Looking forward to known your suggestions.
Thanks in advance.
TL;DR version: Compile to C++20 or a more recent version of the C++ Standard where both compilers should accept this code. Downside: you may find other discrepancies between their handling of C++20 and be no better off.
Explanation:
Quoting cppreference
for the constructor of a class or struct, every base class sub-object and every non-variant non-static data member must be initialized.
This is valid until C++20. As of C++20, the code should work as presented (but danged if I know what you'll do with a constant uninitialized variable i. Have to dig into the Standard or deeper into cppreference to see if i is zero initialized or something. This experiment with Matt Godbolt's compiler Explorer suggests it's not initialized.
So the fix is most likely to initialize i.
class Foo
{
public:
constexpr Foo() = default;
~Foo() = default;
Foo(const Foo&) = delete;
private:
int i = 0;
};
MSVC's ability to compile this code prior to C++20 appears to be a bug that could be fixed at any time. Rather than forcing incorrect behaviour onto clang-cl I recommend fixing the code (or compiling both sides to C++20 or more recent.

Overload-Resolution: Is a direct conversion operator preferred (as a consequence of copy-elision)?

Given
struct E
{
};
struct P
{
explicit P(E) {}
};
struct L
{
operator E() {return {};}
operator P() {return P{E{}};}
};
According to the C++17 language standard, should the expression P{L{}} compile?
Different compilers produce different results:
gcc (trunk): ok
gcc 8.3: error (overload ambiguous)
gcc 7.4: ok
clang (trunk): ok
clang 8.0.0: ok
clang 7.0.0: ok
msvc v19.20: error (overload ambiguous)
icc 19.0.1: error (more than one constructor instance matches)
I think the correct behavior per the standard is to be ambiguous.
[dcl.init]/17.1:
If the initializer is a (non-parenthesized) braced-init-list or is = braced-init-list, the object or reference is list-initialized.
[dcl.init.list]/3.6:
Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution ([over.match], [over.match.list]). If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed.
And [over.match.list] just talks about picking a constructor. We have two viable options: P(E) by way of L{}.operator E() and P(P&&) (the implicit move constructor) by way of L{}.operator P(). None is better the other.
However, this is very reminiscent of CWG 2327:
struct Cat {};
struct Dog { operator Cat(); };
Dog d;
Cat c(d);
Which as the issue indicates currently invokes Cat(Cat&&) instead of just d.operator Cat() and suggests that we should actually consider the conversion functions as well. But it's still an open issue. I'm not sure what gcc or clang did in response to this issue (or in response to similar examples that got brought up first), but based on your results I suspect that they decide that the direct conversion function L{}.operator P() is a better match and just do that.

type conversion operator not being used to cast, compilers differ

How does the C++ compiler decide which type conversion operator or constructor to use when casting from one class to another? Why would this behavior change from compiler to compiler?
EDIT: B::operator ClassA() should be public, fixed.
EDIT2: After further investigation, I think I'm making a bit of progress:
The full error message for the first example code is as follows:
file1.cc:123:45 error: call of overloaded 'ClassA(ClassB&)' is ambiguous
someFunction( ( (ClassA) cbObject ).methodOfClassA() )
file1.cc:123:45 notes: candidates are:
In file included from ...:
/path/to/file/class_a.hh:123:4: note: ClassA::ClassA( some_type )
/path/to/file/class_a.hh:133:4: note: ClassA::ClassA( some_other_type )
The important part is that ClassB also has type conversion operators for some_type and some_other_type. If I comment out the type conversion operator for some_type, the compiler no longer lists that as a candidate for the ClassA(ClassB&) call.
This means that the compiler is using ClassB's operators to convert ClassB to some intermediate type, and then calling ClassA's constructor using that type, rather than using ClassB's operator ClassA(). I'm not still not sure why though...
End of EDIT2
I'm attempting to port some code that was written for Solaris onto Linux. It compiles and runs fine on Solaris, but I'm getting some compiler errors on Linux.
Solaris compiler: CC: Sun C++ 5.11
Linux compiler: gcc version 4.8.2
Here's the relevant code:
class_a.hh
class ClassA
{
public:
// Several constructors, none of which take a ClassB
ClassA( some_type source )
...
ClassA( some_other_type source )
...
}
class_b.hh
class ClassB
{
public:
// constructors and such
...
virtual operator ClassA() const throw();
...
}
class_b.cc
ClassB::operator ClassA() const throw()
{
ClassA newClassA;
// logic to initialize classA with classB's data
return newClassA;
}
The code that uses these classes is littered with casts from ClassB to ClassA. Some examples:
ClassB cbObject;
// cbObject is initialized with data somehow
someFunction( ( (ClassA) cbObject ).methodOfClassA() )
or passing a ClassB to a function that takes a ClassA
int someOtherFunction( ClassA caObject )
{
...
}
...
ClassB cbObject;
// cbObject initialized with data somehow
int someNumber = someOtherFunction( cbObject );
Once again, on Solaris this all compiles and runs fine, and does what is expected of it. However, on Linux I get errors like the following:
For the first example code, I get this error:
file1.cc:123:45 error: call of overloaded 'ClassA(ClassB&)' is ambiguous
For the second, I get this:
file2.hh:234:56 note: no known conversion for argument 1 from 'ClassB' to 'ClassA'
file2.cc:123:45 error: no matching function for call 'SomeOtherClass::someFunction(ClassB&)'
When I commented out the type conversion operator in ClassB, it would no longer compile on Solaris and the error messages all obviously pointed to this operator being missing. The error messages on Linux did not change.
According to this: Conversion constructor vs. conversion operator: precedence, it should look at both the operator and constructors and only complain about ambiguity when they are equally useful, right?
And also according to this: conversion operator overloading ambiguity, compilers differ, compilers having different behaviors when casting is likely because one tries harder to find different ways the cast could be completed, but it strikes me as odd that gcc would not even look for the type conversion operator after failing to find a suitable constructor.
Why doesn't the compiler use ClassB's ClassA operator to cast from ClassB to ClassA on Linux, when it does on Solaris?
A conversion creates a temporary object; temporaries can't bind to non-const lvalue references. (This appears not to apply to your "example" code, but the error messages don't exactly match the examples either, so it's difficult to tell whether this is the cause).
There are a number of popular compilers that get this wrong and allow improper code.
In addition, accessibility checks are performed on conversion operators. In your example, the B::operator ClassA() is private. However, this should be mentioned in the error message.

Constructor and initializer_list

Could somebody tell me the theory behind this?
Why the last call doesn't compile?
test.cc: In function ‘int main()’: test.cc:15:12: error: too many braces around initializer for ‘int’ [-fpermissive] test.cc:15:12:
error: invalid conversion from ‘’ to ‘int’ [-fpermissive] test.cc:9:6: error: initializing argument 1 of ‘void f(std::initializer_list)’ [-fpermissive] test.cc:15:12:
error: aggregate value used where an integer was expected
I think either c++11 or g++ 4.7 is broken on this.
Thank you!
#include <initializer_list>
class A {
public:
A(const std::initializer_list<int>) {}
};
void f(const std::initializer_list<int>) {}
int main() {
A({1}); // Compile OK
f({1}); // Compile OK
A({{{1}}}); // Compile OK
//f({{{1}}}); // Compile Error.
}
Here is what I believe GCC is thinking.
This is your program with 1 extra line, and the interesting lines numbered.
int main() {
A({1}); // 1. Compile OK
f({1}); // 2. Compile OK
A{{1}}; // 3. Compile OK, equivalent to 1.
A({{{1}}}); // 4. Compile OK
//f({{{1}}}); // 5. Compile Error.
}
Why does GCC compile 4 but not 5?
For clarity, suppose the construction at #4 actually declared something:
A a{{{1}}}; // 4a. Compile OK
GCC asks if the argument of the constructor, which is {{1}} is
implicitly convertible to A. So is:
A{{1}}
a valid conversion from {{1}} to A? Yes it is - as per 3.
This reasoning, of course, is not applicable to #5; hence error.
If you want to stop GCC from accepting #4, then block the
enabling conversion by making the enabling constructor explicit:
class A {
public:
explicit A(const std::initializer_list<int> il) {}
};
Then #4 will give the error:
error: converting to ‘A’ from initializer list would use explicit constructor ‘A::A(std::initializer_list<int>)’
A {1} can initialize an int. A {{1}} probably should not - there is a defect report on tbe committee for that. GCC forbids that and clang just tends to emit warnings about redundant braces currently.
When X is a class that has copy or move constructors, then X ({...}) may invoke invoke one of them. Notice that X {...} may too, but is restricted to not allow user defined conversions (for a copy or move constructor).
Now with your A ({{{1}}}) the first brace is consumed by the copy/move constructor. The second goes to the initializer list recursively. And the third goes to the contained int.
According to the Standard, adding one more brace will break for A ({{{{1}}}}). Because the second brace would need to be consumed by a copy/move constructor of A but need a user defined conversion sequence. The same holds for A {{{{1}}}}, which is invalid for this reason too.

Copy Constructor Needed with temp object

The following code only works when the copy constructor is available.
When I add print statements (via std::cout) and make the copy constructor available it is not used (I assume there is so compiler trick happening to remove the unnecessary copy).
But in both the output operator << and the function plop() below (where I create a temporary object) I don't see the need for the copy constructor. Can somebody explain why the language needs it when I am passing everything by const reference (or what I am doing wrong).
#include <iostream>
class N
{
public:
N(int) {}
private:
N(N const&);
};
std::ostream& operator<<(std::ostream& str,N const& data)
{
return str << "N\n";
}
void plop(std::ostream& str,N const& data)
{
str << "N\n";
}
int main()
{
std::cout << N(1); // Needs copy constructor (line 25)
plop(std::cout,N(1)); // Needs copy constructor
N a(5);
std::cout << a;
plop(std::cout,a);
}
Compiler:
[Alpha:~/X] myork% g++ -v
Using built-in specs.
Target: i686-apple-darwin10
Configured with: /var/tmp/gcc/gcc-5646~6/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10
Thread model: posix
gcc version 4.2.1 (Apple Inc. build 5646)
[Alpha:~/X] myork% g++ t.cpp
t.cpp: In function ‘int main()’:
t.cpp:10: error: ‘N::N(const N&)’ is private
t.cpp:25: error: within this context
t.cpp:10: error: ‘N::N(const N&)’ is private
t.cpp:26: error: within this context
This is a simplified version of some real code.
In the real code I have a class that contains a std::auto_ptr. This means that a copy constructor that takes a const reference is not valid (without some work) and I was getting an error indicating that the copy constructor was not available because of it:
Change the class too:
class N
{
public:
N(int) {}
private:
std::auto_ptr<int> data;
};
The error is then:
t.cpp:25: error: no matching function for call to ‘N::N(N)’
From http://gcc.gnu.org/gcc-3.4/changes.html
When binding an rvalue of class type
to a reference, the copy constructor
of the class must be accessible. For
instance, consider the following code:
class A
{
public:
A();
private:
A(const A&); // private copy ctor
};
A makeA(void);
void foo(const A&);
void bar(void)
{
foo(A()); // error, copy ctor is not accessible
foo(makeA()); // error, copy ctor is not accessible
A a1;
foo(a1); // OK, a1 is a lvalue
}
This might be surprising at first
sight, especially since most popular
compilers do not correctly implement
this rule (further details).
This will be fixed in C++1x by Core Issue 391.
The applicable parts of the standard here are §8.5.3/5, which covers initialization of references and §3.10/6, which tells what's an rvalue and what's an lvalue (not always obvious in C++).
In this case, you initialization expression is: "N(1)", so you're explicitly creating an object using functional notation. According to 3.10/6, that expression is an rvalue.
Then we have to walk through the rules in 8.5.3/5 in order, and use the first that applies. The first possibility is if the expression represents an lvalue, or can be implicitly converted to an lvalue. Your expression is an rvalue, and implicit conversion to an lvalue would require a conversion function that returns a reference, which doesn't seem to exist in this case, so that doesn't seem to apply.
The next rule says the reference must be to a const T (which is the case here). In this case, the expression is an rvalue of class type and is reference-compatible with the reference (i.e. the reference is to the same class, or a base of the class). That means the bullet at the bottom of page 151 (179 of the C++ 2003 PDF) seems to apply. In this case, the compiler is allowed to either bind the reference directly to the object representing the rvalue, OR create a temporary copy of the rvalue, and bind to that temporary copy.
Either way, however, the standard explicitly requires that: "The constructor that would be used to make the copy shall be callable whether or not the copy is actually done."
As such, I believe that gcc is right to give an error message, and the others are technically wrong to accept the code. I simplified your code a bit to the following:
class N {
public:
N(int) {}
private:
N(N const&);
};
void plop(N const& data) { }
int main() {
plop(N(1));
}
When invoked with "--A" (strict errors mode), Comeau gives the following error message:
"plop.cpp", line 12: error: "N::N(const N &)", required for copy that was
eliminated, is inaccessible
plop(N(1));
^
Likewise, when invoked with "/Za" (its "ANSI conforming" mode), VC++ 9 gives:
plop.cpp
plop.cpp(12) : error C2248: 'N::N' : cannot access private member declared in class 'N'
plop.cpp(6) : see declaration of 'N::N'
plop.cpp(2) : see declaration of 'N'
while checking that elided copy-constructor 'N::N(const N &)' is callable
plop.cpp(6) : see declaration of 'N::N'
when converting from 'N' to 'const N &'
My guess is that most of the other compilers do roughly the same. Since they optimize out the call to the copy constructor, they don't normally require that it exist or be accessible. When you ask them to conform to the standard as accurately as they can, they give the error message, because it's technically required even though they don't use it.