When attempting to delete the default constructor and provide a new one with a default parameter (and therefore still be able to default construct the object), I receive an ambiguity error from g++.
class Thing
{
public:
Thing() = delete;
Thing(int arg = 0) : arg(arg) {}
private:
int arg;
};
int main(int, char**)
{
Thing thing;
return 0;
}
Compilation error below:
$ g++ deletedConstructorTest.C -std=c++11
deletedConstructorTest.C: In function "int main(int, char**)":
deletedConstructorTest.C:12:9: error: call of overloaded "Thing()" is ambiguous
Thing thing;
^
deletedConstructorTest.C:12:9: note: candidates are:
deletedConstructorTest.C:5:5: note: Thing::Thing(int)
Thing(int arg = 0) :arg(arg) {}
^
deletedConstructorTest.C:4:5: note: Thing::Thing() <deleted>
Thing() = delete;
^
If I modify the example above by removing the "Thing() = delete;" line then it compiles fine. I understand that the compiler won't generate a default constructor since I provided my own so that line is unnecessary but I was surprised at the compilation error.
Thanks in advance!
All declared overloads are considered during overload resolution, even if they are deleted or inaccessible. So you've declared two default constructors, both of which are an equally good match for default-initialisation, hence the ambiguity.
In this case, simply don't declare the zero-argument default constructor at all. The one-argument constructor is usable as a default constructor, and declaring any constructor inhibits the generation of an implicit default constructor.
Related
Let's have this code using gmock 1.8:
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include <variant>
class Obj {
public:
MOCK_METHOD0( mock, void() );//<-!!!
};
using Variant = std::variant<Obj>;
TEST(Test, Test) {
Obj obj;
Variant variant = obj;
}
When trying to compile this with clang++ there is this compile error:
error: no viable conversion from 'Obj' to 'Variant' (aka 'variant<Obj>')
Variant variant = obj;
^ ~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/variant:1081:7: note: candidate constructor not viable: no known conversion from 'Obj' to 'const std::variant<Obj> &' for 1st argument
variant(const variant& __rhs) = default;
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/variant:1093:2: note: candidate template ignored: substitution failure [with _Tp = Obj &, $1 = void, $2 = void]: implicit instantiation of undefined template 'std::variant<Obj>::__to_type_impl<18446744073709551615, false>'
variant(_Tp&& __t)
^
(g++'s error only says
error: conversion from ‘Obj’ to non-scalar type ‘Variant’ {aka ‘std::variant<Obj>’} requested
Variant variant = obj;
^~~
)
When the line with MOCK_METHOD0 macro is commented out, the code compiles all right. I'm convinced it's the copy constructor (the one from line 1081) that gets invoked in that case.
Why is that? Will the problem disappear if I move to gmock 1.10? Or is it impossible to use variants of gmock mocks? Thanks for any explanation or a hint on how to find it myself.
If you expand the MOCK_METHOD0 macro, you will see that it inserts the following data member to your class definition:
class Obj
{
public:
// ...
mutable ::testing::FunctionMocker<void()> gmock0_mock_12;
};
Since you do not provide your own copy-constructor, one will be implicitly generated by the compiler. Its default implementation will try to perform a member-wise copy. However, checking the definition of FunctionMocker, one can see the following notice:
// There is no generally useful and implementable semantics of
// copying a mock object, so copying a mock is usually a user error.
// Thus we disallow copying function mockers. If the user really
// wants to copy a mock object, they should implement their own copy
// operation, for example:
//
// class MockFoo : public Foo {
// public:
// // Defines a copy constructor explicitly.
// MockFoo(const MockFoo& src) {}
// ...
// };
FunctionMocker(const FunctionMocker&) = delete;
FunctionMocker& operator=(const FunctionMocker&) = delete;
That is, FunctionMocker objects are non-copyable, and so are mock objects (their implicitly generated copy-constructors are also deleted).
That's reasonable. Should a copy of a mock have the same expectations? Should it double-check the expectations on destruction?
If you want to put the mock in a variant, you can build it in-place, either:
std::variant<Obj> variant(std::in_place_type_t<Obj>{});
or:
std::variant<Obj> variant;
variant.emplace<Obj>();
This is a similar question to others, BUT I have checked what this is being flagged as a duplicate as, and the general responses aren't helping me because I either do not understand them or they are irrelevant to my issue. I need help and/or a solution specifically to this problem. Please and thank you.
I am building a "programming language" (but it isn't really, just don't know how to describe it), and in my ContainerList class I keep getting this error saying that there is no matching call for function. Why am I getting this error?
I've tried manipulating where and when the constructor is used or defined or if it even exists. But there seems to be no luck. I looked into the MemoryContainer class and it doesn't seem like there is anything to cause the error.
Here is my code for the ContainerList class:
#include "MemoryContainer.cpp"
struct ContainerListItem{
int index = 0;
MemoryContainer item;
ContainerListItem* nextItem;
ContainerListItem(byte none) {}
};
class ContainerList{
public:
int getSize() {return size;}
void addContainer(MemoryContainer item){
ContainerListItem indexItem = ContainerListItem(1);
indexItem.item = item;
indexItem.index = size - 1;
indexItem.nextItem = &firstItem;
firstItem = indexItem;
size++;
}
MemoryContainer getContainer(int index){
ContainerListItem currentItem = ContainerListItem(1);
currentItem = firstItem;
while(currentItem.index != index)
currentItem = *currentItem.nextItem;
return currentItem.item;
}
private:
int size = 1;
ContainerListItem firstItem = ContainerListItem(1);
};
full error for the defined constructor:
In file included from Main.cpp:1:
ContainerList.cpp: In constructor ‘ContainerListItem::ContainerListItem(uint8_t)’:
ContainerList.cpp:7:34: error: no matching function for call to ‘MemoryContainer::MemoryContainer()’
ContainerListItem(byte none) {}
^
In file included from ContainerList.cpp:1,
from Main.cpp:1:
MemoryContainer.cpp:24:5: note: candidate: ‘MemoryContainer::MemoryContainer(uint64_t, std::__cxx11::string)’
MemoryContainer(lint ContainerSize, string name){
^~~~~~~~~~~~~~~
MemoryContainer.cpp:24:5: note: candidate expects 2 arguments, 0 provided
MemoryContainer.cpp:17:7: note: candidate: ‘MemoryContainer::MemoryContainer(const MemoryContainer&)’
class MemoryContainer{
^~~~~~~~~~~~~~~
MemoryContainer.cpp:17:7: note: candidate expects 1 argument, 0 provided
MemoryContainer.cpp:17:7: note: candidate: ‘MemoryContainer::MemoryContainer(MemoryContainer&&)’
MemoryContainer.cpp:17:7: note: candidate expects 1 argument, 0 provided
Your ContainerListItem class has a member that's another class:
MemoryContainer item;
However the constructor does not initialize it at all:
ContainerListItem(byte none) {}
The constructor is mostly empty.
All members of a class must be initialized by its constructor. If the constructor does not explicitly initialize a class member, it must have a default constructor that initializes it. A default constructor is a constructor that takes no parameters.
You did not show the declaration of your MemoryContainer class, but it must have a constructor that takes at least one parameter (actually there might be a few other reasons too, but this is the most likely one).
Which means that ContainerListItem must either explicitly initialize the class member, by constructing it, or you must add a default constructor to MemoryContainer.
This is exactly what your compiler is telling you, if you carefully read its error message:
error: no matching function for call to
‘MemoryContainer::MemoryContainer()’
The compiler is telling you that this class's default constructor does not exist. Because ContainerListItem does not explicitly initialize this class member, its default constructor must be called. But it's not declared.
You will find more information about the different ways of initializing class members in your C++ book. But if, for example, MemoryContainer's only constructor takes an int parameter, and you wish to initialize it, in this case, by calling its constructor with 0, your ContainerListItem constructor would read (using modern C++ uniform initialization syntax):
ContainerListItem(byte none) : item{0} {}
You need to figure out whether you want to implement a default constructor for MemoryContainer, or how to initialize it here. Nobody else can figure it out for you, this is a decision that only you can make.
I've got this short snippet of code that I'd like to get a bit more information about as to why overload resolution is picking one constructor over another. Here's the code in question:
#include <iostream>
struct Base
{
};
struct Other
{
Other(const Other&)
{
std::cout << "Copy Constructor\n";
}
Other(const Base&)
{
std::cout << "Custom Constructor\n";
}
};
struct Derived : public Base, public Other
{
Derived() :
Other(*this)
{
}
};
int main()
{
Derived derived; // Prints "Copy Constructor"
system("pause");
return 0;
}
I'm assuming there's a section in the C++ Standard that defines the copy constructor as a better match than user defined constructors*? My assumption otherwise was that if no rule favoring the copy constructor existed, then the compiler would either go by the order of inheritance (as with the order of construction with multiple inheritance) or just give me an ambiguous constructor call error. However, reversing the order in which Derived inherits from Base and Other doesn't change the output, which leads me to believe that my initial guess about copy constructors being favored is correct. Could anyone point me to the rule that determines the behavior I'm seeing?
* I checked cppreference.com's Overload Resolution page, but I didn't see any rule listed there that would explain the behavior I'm seeing (though I'm
not completely fluent in Standardese, so I could have easily missed it).
The reason that the code snippet in question compiles is due to non-standard conforming behavior from Visual Studio (I'm currently using VS2017.3 Preview, which compiles the code without errors even with the /permissive- flag). Below is the error emitted by GCC and Clang:
GCC
Error(s):
source_file.cpp: In constructor ‘Derived::Derived()’:
source_file.cpp:25:20: error: call of overloaded ‘Other(Derived&)’ is ambiguous
Other(*this)
^
source_file.cpp:16:5: note: candidate: Other::Other(const Base&)
Other(const Base&)
^
source_file.cpp:12:5: note: candidate: Other::Other(const Other&)
Other(const Other&)
^
Clang
Error(s):
source_file.cpp:25:9: error: call to constructor of 'Other' is ambiguous
Other(*this)
^ ~~~~~
source_file.cpp:12:5: note: candidate constructor
Other(const Other&)
^
source_file.cpp:16:5: note: candidate constructor
Other(const Base&)
^
1 error generated.
Error output taken from http://rextester.com/.
I have the following class:
class Fraction {
private:
int x;
int y;
public:
// Constructors
Fraction(long x = 0, long y = 1);
Fraction(const Fraction&)=default;//here is the problem
virtual ~Fraction();
};
I'm trying to disable default C++ constructor to implement my own (I intend to use it for copy). So, I declared it as a default. But, when I'm trying to implement it:
Fraction::Fraction(const Fraction&){}
Compiler throws the following error at me:
./src/Fraction.cpp:16:1: error: definition of explicitly-defaulted
‘Fraction::Fraction(const Fraction&)’ Fraction::Fraction(const
Fraction&){ ^ In file included from ../src/Fraction.cpp:8:0:
../src/Fraction.h:22:2: error: ‘Fraction::Fraction(const Fraction&)’
explicitly defaulted here Fraction(const Fraction&)=default;
Is there any way to fix it? What I'm doing wrong ? I found some articles about defaults, but nothing that can help me fix these errors.
= default tells the compiler to use the default implementation. This also means that you cannot provide your own. If you don't want the compiler to create one, simply remove = default:
class Fraction {
// ...
Fraction(const Fraction&); // NO =default
};
By the way, the "default constructor" is the one that's called when you don't provide any arguments, e.g.
Fraction my_frac; // default constructor called
If you want to disable the default constructor, use =delete:
class Fraction{
public:
Fraction() = delete;
}
Keep in mind that your current Fraction(long, long) provides default arguments, so it's eligible as a default constructor.
I've got a compiler error but I can't figure out why.
the .hpp:
#ifndef _CGERADE_HPP
#define _CGERADE_HPP
#include "CVektor.hpp"
#include <string>
class CGerade
{
protected:
CVektor o, rv;
public:
CGerade(CVektor n_o, CVektor n_rv);
CVektor getPoint(float t);
string toString();
};
the .cpp:
#include "CGerade.hpp"
CGerade::CGerade(CVektor n_o, CVektor n_rv)
{
o = n_o;
rv = n_rv.getUnitVector();
}
the error message:
CGerade.cpp:10: error: no matching function for call to ‘CVektor::CVektor()’
CVektor.hpp:28: note: candidates are: CVektor::CVektor(float, float, float)
CVektor.hpp:26: note: CVektor::CVektor(bool, float, float, float)
CVektor.hpp:16: note: CVektor::CVektor(const CVektor&)
CGerade.cpp:10: error: no matching function for call to ‘CVektor::CVektor()’
CVektor.hpp:28: note: candidates are: CVektor::CVektor(float, float, float)
CVektor.hpp:26: note: CVektor::CVektor(bool, float, float, float)
CVektor.hpp:16: note: CVektor::CVektor(const CVektor&)
From the looks of it, your CVektor class has no default constructor, which CGerade uses in your constructor:
CGerade::CGerade(CVektor n_o, CVektor n_rv)
{ // <-- by here, all members are constructed
o = n_o;
rv = n_rv.getUnitVector();
}
You could (and probably should) add one, but better is to use the initialization list to initialize members:
CGerade::CGerade(CVektor n_o, CVektor n_rv) :
o(n_o),
rv(n_rv.getUnitVector())
{}
Which specifies how the members are initialized. (And above, it was defaulting to the non-existent default-constructor.)
Your CVektor class has no default constructor (that is, one that takes no arguments), so your CGerade constructor can't call it. Since you're not explicitly calling a CVektor constructor in your initializer list, the compiler implicitly tries to call the default constructor, but there is none to call, so you get an error.
You should explicitly call the CVektor copy constructor using an initializer list:
CGerade::CGerade(CVektor n_o, CVektor n_rv)
: o(n_o), rv(n_rv.getUnitVector())
{
// empty body
}