I'm getting the error:
error: no matching function for call to 'A::A()'
note: candidates are: A::A(const A&)
note: A::A(const std::string&, size_t)
From this:
#include <map>
#include <string>
using std::map;
using std::string;
class A {
public:
string path;
size_t size;
A (const string& p, size_t s) : path(p), size(s) { }
A (const A& f) : path(f.path), size(f.size) { }
A& operator=(const A& rhs) {
path = rhs.path;
size = rhs.size;
return *this;
}
};
int main(int argc, char **argv)
{
map<string, A> mymap;
A a("world", 1);
mymap["hello"] = a; // <----- here
A b(mymap["hello"]); // <----- and here
}
Please tell me why the code wants a constructor with no parameters.
Because map requires DefaultConstructible values, since when using subscript operator and the key is not found it adds it mapped to a default constructed value.
In general a default constructor is not required for a map item value.
It was required in C++03, but that requirement was dropped in C++11, which often instead of posing container-wide requirements uses a more fine grained requirement scheme with requirements on the use of particular member functions.
The map::operator[] is one such member function, because it will create an item with the given key and a default-constructed value, if an item with the key doesn't exist.
This is also the reason why there isn't a const version of map::operator[]: it potentially modifies the map.
In C++11 and later you can use the at accessor to access an item with a given key in a const map, without the verbosity & complexity of a find.
Since map::at doesn't attempt to create an item, it doesn't require the item type to be default constructible.
And so one practical solution for your problem is to use map::at instead of map::operator[].
mymap["hello"] can attempt to create a value-initialized A, so a default constructor is required.
If you're using a type T as a map value (and plan to access value via operator[]), it needs to be default-constructible - i.e. you need a parameter-less (default) constructor. operator[] on a map will value-initialize the mapped value if a value with the key provided is not found.
Long time without using C++, but If I recall correctly if you don't define a constructor for a class the compiler will create a paramless one for you. As soon as you define a constructor with parameters the compiler won't create a paramless one for you, so, you are required to create one. This added to what K-ballo exposed leads to your errors.
Related
#include <iostream>
#include <vector>
#include <array>
#define Nbodies 3
class Assembly {
public:
// initializing constructor
Assembly(double _dataA)
: data(_dataA), AssA(nullptr), AssB(nullptr) { }
// double argument copy constructor
Assembly(Assembly &A, Assembly&B)
: AssA(&A), AssB(&B) {
data = A.data * B.data;
}
// single argument copy constructor - generates errors once uncommented
/*
Assembly(Assembly &A)
: data(A.data), AssA(&A), AssB(&A) {
// initialize other members of this class here
}
*/
double data;
private:
// these are const pointers to non-const objects of a type Assembly
Assembly *const AssA, *const AssB;
};
int main() {
std::array<double, Nbodies> datas = {1.0, 2.0, 3.0};
// Initilize first branch of the binary tree
std::vector<Assembly> base_assembly;
for (int i = 0; i < Nbodies; i++) {
base_assembly.emplace_back(datas[i]);
}
// Binary tree assembly - MWE (for general case, I'm using nested for loop)
Assembly AssemblyAB = Assembly(base_assembly[0], base_assembly[1]);
Assembly AssemblyC = Assembly(base_assembly[2]);
Assembly AssemblyS = Assembly(AssemblyAB, AssemblyC);
std::cout << AssemblyS.data << std::endl;
return 0;
}
I'm working on a program that generates a binary try recursively. When I have a branch with an odd number of elements, I need to "rewrite" an element to a lower branch. For this, I use a copy constructor since I need to initialize additional members of the class (I'm using the Eigen library, and some operations can not be done as a one-liner in the initialization list).
My problem arose when I defined a singe argument copy constructor. I get the following error:
.../mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/bits/stl_construct.h:75:7:
error:
cannot bind non-const lvalue reference of type 'Assembly&' to
an rvalue of type 'Assembly'
Why defining a single argument copy constructor generates such an error? Note that in the case of a two-argument copy constructor the are no errors at all.
A typical copy constructor takes const T&, or in this case const Assembly&.
Since you don't have that, there is no way for standard library containers such as std::vector to copy your type, which it would need to do if it ever needs to reallocate the array (e.g. to make it bigger).
However, std::vector<T> where T has a noexcept move constructor will use the move constructor instead, thus avoiding the problem of not having a copy constructor.
Thus the following addition allows this to work:
Assembly(Assembly&&) noexcept = default; // generate a noexcept move constructor
Note that this will result in the newly-constructed object also pointing to the same AssA and AssB objects.
As a side note, I would recommend renaming those to AsmA and AsmB if only to deter snickering.
Edit:
At the very root, the problem is with that single parameter Assembly& constructor, which is causing the copy constructor to not be implicitly generated. The similarity to the copy constructor is also bad due to being unintuitive. Assembly thing = other; would actually call the weird Assembly&constructor when you would expect it to just copy. Thus the best answer to the problem is just to get rid of it.
Option 1: When you want that behavior, just use the 2 parameter constructor and pass the same object twice.
Option 2: Make it a tag constructor:
// the tag type we'll use to select the weird constructor
inline struct same_asm_t {} same_asm; // not sure what version of C++ you're on; if this doesn't work remove inline and define in a cpp file elsewhere
// define this as a tag constructor (take some other "tag" type as a param for overload resolution)
Assembly(Assembly &A, same_asm_t) : data(A.data), AssA(&A), AssB(&A) {}
// use it like this, where other is an instance of Assembly
Assembly thing(other, same_asm);
I'm getting the error:
error: no matching function for call to 'A::A()'
note: candidates are: A::A(const A&)
note: A::A(const std::string&, size_t)
From this:
#include <map>
#include <string>
using std::map;
using std::string;
class A {
public:
string path;
size_t size;
A (const string& p, size_t s) : path(p), size(s) { }
A (const A& f) : path(f.path), size(f.size) { }
A& operator=(const A& rhs) {
path = rhs.path;
size = rhs.size;
return *this;
}
};
int main(int argc, char **argv)
{
map<string, A> mymap;
A a("world", 1);
mymap["hello"] = a; // <----- here
A b(mymap["hello"]); // <----- and here
}
Please tell me why the code wants a constructor with no parameters.
Because map requires DefaultConstructible values, since when using subscript operator and the key is not found it adds it mapped to a default constructed value.
In general a default constructor is not required for a map item value.
It was required in C++03, but that requirement was dropped in C++11, which often instead of posing container-wide requirements uses a more fine grained requirement scheme with requirements on the use of particular member functions.
The map::operator[] is one such member function, because it will create an item with the given key and a default-constructed value, if an item with the key doesn't exist.
This is also the reason why there isn't a const version of map::operator[]: it potentially modifies the map.
In C++11 and later you can use the at accessor to access an item with a given key in a const map, without the verbosity & complexity of a find.
Since map::at doesn't attempt to create an item, it doesn't require the item type to be default constructible.
And so one practical solution for your problem is to use map::at instead of map::operator[].
mymap["hello"] can attempt to create a value-initialized A, so a default constructor is required.
If you're using a type T as a map value (and plan to access value via operator[]), it needs to be default-constructible - i.e. you need a parameter-less (default) constructor. operator[] on a map will value-initialize the mapped value if a value with the key provided is not found.
Long time without using C++, but If I recall correctly if you don't define a constructor for a class the compiler will create a paramless one for you. As soon as you define a constructor with parameters the compiler won't create a paramless one for you, so, you are required to create one. This added to what K-ballo exposed leads to your errors.
I am trying to initialize a STL map using C++11 syntax but that doesn't seem to work. After initialization, when i try to access the element, it tries to call the private constructor of Foo. Did I miss something? It works if I use at. I am wondering if I could use operator[] to access initialized values...
#include <map>
#include <string>
class Foo{
public:
int a, b;
Foo(int a_, int b_){
a = a_;
b = b_;
}
private:
Foo(){};
};
int main(){
std::map<std::string, Foo> myMap = { {"1", Foo(10,5)}, {"2", Foo(5,10)} };
int b = myMap["1"].b; // it tries to call private constructor of Foo.
return 0;
}
When you use the operator[] on a map, you may use the operator to either get a value from the map or assign a value into the map. In order to assign the value into the map, the map has to construct an object of its value type, and return it by reference, so that you can use operator= to overwrite an existing object.
Consequently, the type has to be default constructible so that a new object can be created for you to assign into.
At run time, the constructor won't be called if the key already exists, but the compiler has no way of knowing whether you'll ever use operator[] to access a value that doesn't exist, so it requires the constructor to be public.
operator[] of map requires the type to be default constructible, because it creates a new entry if one doesn't exist.
You can use at() instead, which throws if the entry doesn't exist:
int b = myMap.at("1").b;
This is my CreateCustomer method:
CustomerData Database::createCustomer(std::string const& name) {
CustomerData data(customersDb.size()+1, name);
customersDb[data.number()] = data;
// customersDb.insert(std::pair<uint, CustomerData>(data.number(), data));
return data;
}
Constructor of class CustomerData:
CustomerData::CustomerData(uint number, std::string const& name) {
m_number = number;
m_name = name;
}
Incorrect line is this one:
customersDb[data.number()] = data;
Thing is, the next line works. I can't figure it out and can't use insert because accessing element with [] brackets doesn't work either.
I've tried even creating copy constructor but with no effect:
CustomerData::CustomerData(CustomerData &data) {
m_number = data.number();
m_name = data.name();
}
These are the errors:
Database.cpp:5: instantiated from here
stl_map.h:450: error: no matching function for call to 'CustomerData::CustomerData()'
CustomerData.h:18: candidates are: CustomerData::CustomerData(CustomerData&)
CustomerData.h:17: note: CustomerData::CustomerData(uint, const std::string&)
I use Mingw.
operator[] with the standard map template default-constructs an element with the given key if none already exists.
Your element type has no default constructor, so this cannot happen.
You'll have to use .insert instead.
customersDb.insert(make_pair(data.number(), data));
I can't figure it out and can't use insert because accessing element with [] brackets doesn't work either.
To modify an existing element, retrieve an iterator with .find, dereference and do your thing.
yourMapType::iterator it = customersDb.find(data.number());
if (it != customersDb.end())
*it = data;
It doesn't work because operator[] actually first default constructs the value, and then assigns to it.
You can either provide a default constructor, or use this call:
customersDb.insert( std::map< uint, CustomerData >::value_type (data.number(), data) );
You need to provide a default constructor for your CustomerData class.
CustomerData::CustomerData()
{
}
Or you implement a code in such a way that it only calls the constructor which you have provided for your class. It is needed by [] to default construct an element.
First one looks a better option.
Reason for error:
When you provide any constructor for your own class, the compiler does not generate the default no argument constructor and your code needs one and hence the error.
Read the error, it's in there :)
stl_map.h:450: error: no matching function for call to 'CustomerData::CustomerData()'
It looks like the compiler thinks you're not actually passing any information to the function.
It does recognize these two alternatives :
CustomerData.h:18: candidates are: CustomerData::CustomerData(CustomerData&)
CustomerData.h:17: note: CustomerData::CustomerData(uint, const std::string&)
But both take arguments, which you're not passing.
You need to make sure there is default (blank) constructor so the type can be constructed without args.
myclass(); //implement somewhere
you can also provide default args
myclass(const std::string& value="hello"); //implement somewhere
in C++11 you can do this
myclass()=default; //implementation will be generated
It is trying to call the constructor on your CustomerData class, but it doesn't exist. I'm pretty sure this is something to do with how the standard map works internally. The value of the map must have a default constructor. This would normally be generated by the compiler, but as you have already provided another constructor it was not generated.
Given a class like this:
class Foo
{
const int a;
};
Is it possible to put that class in a vector? When I try, my compiler tells me it can't use the default assignment operator. I try to write my own, but googling around tells me that it's impossible to write an assignment operator for a class with const data members. One post I found said that "if you made [the data member] const that means you don't want assignment to happen in the first place." This makes sense. I've written a class with const data members, and I never intended on using assignment on it, but apparently I need assignment to put it in a vector. Is there a way around this that still preserves const-correctness?
I've written a class with const data members, and I never intended on using assignment on it, but apparently I need assignment to put it in a vector. Is there a way around this that still preserves const-correctness?
You have to ask whether the following constraint still holds
a = b;
/* a is now equivalent to b */
If this constraint is not true for a and b being of type Foo (you have to define the semantics of what "equivalent" means!), then you just cannot put Foo into a Standard container. For example, auto_ptr cannot be put into Standard containers because it violates that requirement.
If you can say about your type that it satisfies this constraint (for example if the const member does not in any way participate to the value of your object, but then consider making it a static data member anyway), then you can write your own assignment operator
class Foo
{
const int a;
public:
Foo &operator=(Foo const& f) {
/* don't assign to "a" */
return *this;
}
};
But think twice!. To me, it looks like that your type does not satisfy the constraint!
Use a vector of pointers std::vector<Foo *>. If you want to avoid the hassle of cleaning up after yourself, use boost::ptr_vector.
Edit: My initial stab during my coffee break, static const int a; won't work for the use case the OP has in mind, which the initial comments confirm, so I'm rewriting and expanding my answer.
Most of the time, when I want to make an element of a class constant, it's a constant whose value is constant for all time and across all instances of the class. In that case, I use a static const variable:
class Foo
{
public:
static const int a;
};
Those don't need to be copied among instances, so if it applied, that would fix your assignment problem. Unfortunately, the OP has indicated that this won't work for the case the OP has in mind.
If you want to create a read-only value that clients can't modify, you can make it a private member variable and only expose it via a const getter method, as another post on this thread indicates:
class Foo
{
public:
int get_a() const { return a; }
private:
int a;
};
The difference between this and
class Foo
{
public:
const int a;
};
is:
The const int gives you assurance that not even the implementation of the class will be able to muck with the value of a during the lifetime of the object. This means that assignment rightfully won't work, since that would be trying to modify the value of a after the object's been created. (This is why, btw, writing a custom operator=() that skips the copy of a is probably a bad idea design-wise.)
The access is different – you have to go through a getter rather than accessing the member directly.
In practice, when choosing between the two, I use read-only members. Doing so probably means you'll be able to replace the value of an object with the value of another object without violating semantics at all. Let's see how it would work in your case.
Consider your Grid object, with a width and height. When you initially create the vector, and let's say you reserve some initial space using vector::reserve(), your vector will be populated with initial default-initialized (i.e. empty) Grids. When you go to assign to a particular position in the vector, or push a Grid onto the end of the vector, you replace the value of the object at that position with a Grid that has actual stuff. But you may be OK with this! If the reason you wanted width and height to be constant is really to ensure consistency between width and height and the rest of the contents of your Grid object, and you've verified that it doesn't matter whether width and height are replaced before or after other elements of Grid are replaced, then this assignment should be safe because by the end of the assignment, the entire contents of the instance will have been replaced and you'll be back in a consistent state. (If the lack of atomicity of the default assignment was a problem, you could probably get around this by implementing your own assignment operator which used a copy constructor and a swap() operation.)
In summary, what you gain by using read-only getters is the ability to use the objects in a vector or any container with value semantics. However, it then falls to you to ensure that none of Grid's internal operations (or the operations of friends of Grid) violate this consistency, because the compiler won't be locking down the width and height for you. This goes for default construction, copy construction, and assignment as well.
I'm considering making the data member non-const, but private and only accessible by a get function, like this:
class Foo
{
private:
int a;
public:
int getA() const {return a;}
};
Is this 'as good' as const? Does it have any disadvantages?
As of c++20, using const member variables are legal without restrictions that had made it virtually unusable in containers. You still have to define a copy assignment member function because it continues to be automatically deleted when a const object exists in the class. However, changes to "basic.life" now allow changing const sub-objects and c++ provides rather convenient functions for doing this. Here's a description of why the change was made:
The following code shows how to define a copy assignment member function which is useable in any class containing const member objects and uses the new functions std::destroy_at and std::construct_at to fulfil the requirement so the new "basic.life" rules. The code demonstrates assignment of vectors as well as sorting vectors with const elements.
Compiler explorer using MSVC, GCC, CLANG https://godbolt.org/z/McfcaMWqj
#include <memory>
#include <vector>
#include <iostream>
#include <algorithm>
class Foo
{
public:
const int a;
Foo& operator=(const Foo& arg) {
if (this != &arg)
{
std::destroy_at(this);
std::construct_at(this, arg);
}
return *this;
}
};
int main()
{
std::vector<Foo> v;
v.push_back({ 2 });
v.push_back({ 1 });
v.insert(v.begin() + 1, Foo{ 0 });
std::vector<Foo> v2;
v2 = v;
std::sort(v2.begin(), v2.end(), [](auto p1, auto p2) {return p1.a < p2.a; });
for (auto& x : v2)
std::cout << x.a << '\n';
}