I am trying to convert a json-Container from the JSON-library JSON for Modern C++ to a vector, but it does not work with the =-operator (I get a compiler error "more than one operator "=" matches these operands").
A minimum working example:
#include "json.hpp"
using json = nlohmann::json;
using namespace std;
int main()
{
vector<double> v = { 0 , 10 , 20 , 100 };
json j(v);
vector<double> copy = j;
vector<double> copyWithAssign;
//copyWithAssign = j; // more than one operator "=" matches these operands
return 0;
}
You can find the json.hpp here.
Using the constructor with vector<double> copy = j; works and I could write copyWithAssign = copy; but that seems dumb. There must be a direct way to assign j to a vector which has been declared and constructed before.
I thought casting might help since the compiler can't decide which type to use. I tried (vector<double>)j, but that didn't help.
One should use
copyWithAssign = j.get<vector<double>>();
Credits go to theodelrieu who posted this answer here.
Related
I got H.W. that in one of the lines of the main.cpp I am suppose to support:
board1[{1,1}]='X';
the logical meaning behind this is to assign to a "game board" the char 'X' at the position of (1,1). I have no clue how to create an array that receives curly brackets such as [{int,int}].
How can I do this?
P.S.
since these are symbols and not chars (and since I don't recognize any term that belongs to this problem) it is very difficult searching for this type of problem in google, so this might be a duplicate :-( , hope not.
I tried to do:
first try:
vector<vector<int> > matrix(50);
for ( int i = 0 ; i < matrix.size() ; i++ )
matrix[i].resize(50);
matrix[{1,1}]=1;
2nd try:
int mat[3][3];
//maybe map
mat[{1,1}]=1;
3rd try:
class _mat { // singleton
protected:
int i ,j;
public:
void operator [](string s)
{
cout << s;
}
};
_mat mat;
string s = "[{}]";
mat[s]; //this does allow me to do assignment also the parsing of the string is a hustle
you need to do something like:
struct coord {
int x;
int y;
};
class whatever
{
public:
//data being what you have in your board
data& operator[] (struct coord) {
//some code
}
};
Your first attempt, was pretty close to working actually. The issue is that the [] operator for the vector takes an integer index into where in the vector you want to change (and the vector must be large enough for it to exist). What you wanted however is a map; which will create the item and assign it for you. Thus a std::map<std::vector<int>, char> would've got you what you wanted. (although it might not have the best performance).
Your second attempted failed for the same reason as the first (index needs to be an integer) and the 3rd is corrected by the answer by Tyker.
I was wondering if it was possible to create an array of objects when the object needs things passed into it for the constructor. I want something like this:
MyClass *myVar;
myVar = new MyClass[num]; // I would like to specify the array size after declaration
int i = 0;
for(i = 0;i < num;i++)
myVar[i] = new MyClass(0,0); // I would also like to populate the array with new objects
I know that this works:
MyClass *myVar;
myVar = new MyClass[num];
but this only works when the constructor has nothing passed into it. Is what I am trying to do possible? If so, how do I do it?
EDIT: I found out how to do it with using arrays. Here is how I did it:
MyClass **myVar;
myVar = new MyClass *[num];
for(i = 0;i < num;i++)
myVar[0] = new MyClass(0,0);
I would use vectors and such but my teacher has told us to use basic arrays whenever possible. The above solution I actually got from some code my teacher wrote. Thank you all for your help!
MyClass *myVar;
myVar = new MyClass[num];
Actually in this form you cannot invoke constructor which takes parameter(s). It is not allowed by the language specification.
However, if you use std::vector, which I recommend you to use, then you can create a vector calling non-default constructor as:
#include <vector> //header file where std::vector is defined
std::vector<MyClass> arr(num, MyClass(10,20));
It creates a vector of num elements, each element is created by calling copy-constructor of the class, passing MyClass(10,20) as argument to it.
The vector is also good because now you dont need to manage memory yourself. Neither manual allocation, nor manual deallocation. Plus, you can know the number of elements by calling arr.size() anytime. You always know how many elements the vector contains. You can also add elements anytime, just by calling .push_back() member function as:
arr.push_back(MyClass(20,30));
And now you can access elements, just like you access array, i.e by using index:
f(arr[i]); // 0 <= i < arr.size();
Additionally, you can use iterators which facilitate idiomatic programming, enabling you to use various algorithmic functions from <algorithm> header as:
#include <algorithm> //header file where std::for_each is defined
std::for_each(arr.begin(), arr.end(), f);
where f is function which takes one argument of type MyClass& (or MyClass const &) depending on what you want to do in f.
In C++11, you can use lambda as:
std::for_each(arr.begin(), arr.end(), [](const MyClass & m)
{
//working with m
});
In C++0x, this grammar works, which can call the non-default constructor in new expression:
MyClass *myVar;
myVar = new MyClass[2]{{10, 20},{20, 30}};
But I doubt if it works when the number of elements in available only at run time.
The vector approach would be better, as shown in Nawaz's answer.
Pointer to pointer is equivalent to 1. array of pointers, and 2. vector<T*> vector of pointers. One way I've done this in the past is using a double pointer. This approach eliminates the overhead of vector data structure and preferred memory efficient is needed.
MyClass ** myvar;
myvar = new Myclass*[num]
for(int i = 0; i < num; i++){
*(myvar+i) = new Myclass(i);}
Works with pretty much any control structure you can imagine. The drawback is that the allocation of memory is not contiguous and my affect speed for large number of num.
You can do something like this too:
MyClass *myVar[num];
for(int i = 0; i < num; i += 1)
{
myVar[i] = new MyClass(0, 0);
}
Actually, you can use a placement new to handle this:
MyClass * myVar;
myVar = reinterpret_cast<MyClass *>(new char[num * sizeof(MyClass)]);
int i = 0;
for (i = 0; i < num; i++) {
new(&myVar[i]) MyClass(0,0);
}
#Nawaz answer is really good about using vectors, but didn't work for me because it create vector of the same objects (all of them reference to the same object)
class Graph
{
public:
Graph(long V); // none default Constructor
}
std::vector<Graph> myGraph;
for (int i = 0; i < T; i++) // read all graphs
{
Graph newGraph(N);
myGraph.push_back(newGraph);
}
I was trying to use vector svec to store some string values. But when compiling at Dev C++ 5.6.1, the compiler reported an error of "no match for operator=". Why is there this error and how to fix it? Thanks.
#include<vector>
#include<iostream>
#include<string>
using namespace std;
int main() {
vector<string> svec[100];
for (int i = 0; i < 100; ++i) {
svec[i] = "ABC";
}
return 0;
}
[Error] no match for 'operator=' (operand types are 'std::vector >' and 'const char [4]')
edit: The problem is in vector svec[100]; Things go well after changing it to vector svec(100);
edit2: I'm curious what the compiler regards this following declaration. Is svec still declared as a vector?
vector<string> svec[100];
vector<string> svec[100]; is creating an array with 100 elements of std::vector<std::string>. That's valid syntax although it's a rather odd thing to do.
In its current form, svec[i] therefore refers to a std::vector<std::string>. Assigning "ABC" to that is not possible. That's why you get the error.
What you mean to write is vector<string> svec(100);. This is calling one of the vector constructors which pre-sizes the vector to have 100 elements.
It just happens that std::vector overloads the [] operator to give you element access. (A rather convenient analogue to pure arrays.) If you make the change, svec[i] will refer to a string which you can set in the way that you currently do.
Change this statement
vector<string> svec[100];
to
vector<string> svec( 100 );
That is instead of an array of 100 vectors you should define a vector of 100 elements.:)
Or you could write simply
vector<string> svec;
// svec.reserve( 100 );
for (int i = 0; i < 100; ++i) {
svec.push_back( "ABC" );
}
And the most simplest way is the following
int main() {
vector<string> svec( 100, "ABC" );
return 0;
}
Well I am questioning myself if there is a way to pass a vector directly in a parameter, with that I mean, like this:
int xPOS = 5, yPOS = 6, zPOS = 2;
//^this is actually a struct but
//I simplified the code to this
std::vector <std::vector<int>> NodePoints;
NodePoints.push_back(
std::vector<int> {xPOS,yPOS,zPOS}
);
This code ofcourse gives an error; typename not allowed, and expected a ')'
I would have used a struct, but I have to pass the data to a Abstract Virtual Machine where I need to access the node positions as Array[index][index] like:
public GPS_WhenRouteIsCalculated(...)
{
for(new i = 0; i < amount_of_nodes; ++i)
{
printf("Point(%d)=NodeID(%d), Position(X;Y;Z):{%f;%f;%f}",i,node_id_array[i],NodePosition[i][0],NodePosition[i][1],NodePosition[i][2]);
}
return 1;
}
Ofcourse I could do it like this:
std::vector <std::vector<int>> NodePoints;//global
std::vector<int> x;//local
x.push_back(xPOS);
x.push_back(yPOS);
x.push_back(zPOS);
NodePoints.push_back(x);
or this:
std::vector <std::vector<int>> NodePoints;//global
std::vector<int> x;//global
x.push_back(xPOS);
x.push_back(yPOS);
x.push_back(zPOS);
NodePoints.push_back(x);
x.clear()
but then I'm wondering which of the two would be faster/more efficient/better?
Or is there a way to get my initial code working (first snippet)?
Use C++11, or something from boost for this (also you can use simple v.push_back({1,2,3}), vector will be constructed from initializer_list).
http://liveworkspace.org/code/m4kRJ$0
You can use boost::assign as well, if you have no C++11.
#include <vector>
#include <boost/assign/list_of.hpp>
using namespace boost::assign;
int main()
{
std::vector<std::vector<int>> v;
v.push_back(list_of(1)(2)(3));
}
http://liveworkspace.org/code/m4kRJ$5
and of course you can use old variant
int ptr[1,2,3];
v.push_back(std::vector<int>(ptr, ptr + sizeof(ptr) / sizeof(*ptr));
If you don't have access to either Boost or C++11 then you could consider quite a simple solution based around a class. By wrapping a vector to store your three points within a class with some simple access controls, you can create the flexibility you need. First create the class:
class NodePoint
{
public:
NodePoint( int a, int b, int c )
{
dim_.push_back( a );
dim_.push_back( b );
dim_.push_back( c );
}
int& operator[]( size_t i ){ return dim_[i]; }
private:
vector<int> dim_;
};
The important thing here is to encapsulate the vector as an aggregate of the object. The NodePoint can only be initialised by providing the three points. I've also provided operator[] to allow indexed access to the object. It can be used as follows:
NodePoint a(5, 6, 2);
cout << a[0] << " " << a[1] << " " << a[2] << endl;
Which prints:
5 6 2
Note that this will of course throw if an attempt is made to access an out of bounds index point but that's still better than a fixed array which would most likely seg fault. I don't see this as a perfect solution but it should get you reasonably safely to where you want to be.
If your main goal is to avoid unnecessary copies of vector<> then here how you should deal with it.
C++03
Insert an empty vector into the nested vector (e.g. Nodepoints) and then use std::swap() or std::vector::swap() upon it.
NodePoints.push_back(std::vector<int>()); // add an empty vector
std::swap(x, NodePoints.back()); // swaps contents of `x` and last element of `NodePoints`
So after the swap(), the contents of x will be transferred to NodePoints.back() without any copying.
C++11
Use std::move() to avoid extra copies
NodePoints.push_back(std::move(x)); // #include<utility>
Here is the explanation of std::move and here is an example.
Both of the above solutions have somewhat similar effect.
So I'm trying to get a sort function to work. It should sort by firstname, but if the first names are the same it should sort by last names. I keep getting an error in mySort() that says "unexpected primary-expression before ')' token" on line where inOrder = arr. What's happening to this and how can I fix it? I need to pass my objects into a function in a seperate class. I'll link them in pastebin.
Here's the driver
#include <iostream>
#include <fstream>
#include <string>
#include "phoneEntry.h"
using namespace std;
void mySort(PhoneEntry& arr, int size)
{
bool inOrder = false;
for (int i = size - 1; i > 0 && !inOrder; i--)
{
inOrder = true;
for (int j = 0; j < i; j++)
{
inOrder = arr.alphaGreater(arr&);
}
}
};
int main()
{
const int MAXNUM = 500;
PhoneEntry entry[MAXNUM];
ifstream filezilla;
filezilla.open("phone.txt");
int count = 0;
if(filezilla)
{
while(count < MAXNUM && entry[count].readEntry(filezilla))
{
count++;
}
mySort(entry&, count);
for(int i = 0; i < count; i++)
{
entry[i].writeEntry(cout) << endl;
}
}
else
{
cout << "Four Oh Four - File Not Found" << endl;
}
return 0;
}
Phone Entry Header
Phone Number Header
Sorting Text (http://pastebin.com/HE8Rsmbg)
You want to pass a reference, so the argument has to be defined as call-by-reference in the function definition/declaration, which is already done:
bool PhoneEntry::alphaGreater(const PhoneEntry& item) const;
As you can see, PhoneEntry::alphaGreater takes a constant PhoneEntry reference. So simply use
inOrder = arr.alphaGreater(arr);
There are several things wrong with your code. The first, the one the
compiler is complaining about, is that there is no postfix operator &
in C++. I don't know exactly what you're trying to do with it, or what
you think it means, but it doesn't exist in C++.
The second is that mySort takes a reference to a single PhoneEntry;
you have an array of PhoneEntry, so you'll have to select one to pass
it. Except that the name of the function and the fact that you pass a
count as well suggest that you really want to pass an array.
And I can't figure out what mySort is supposed to be doing. It
certainly doesn't sort anything; in fact, it seems to be fundamentally
an expensive no-op, since it doesn't return anything, it doesn't modify
arr, and it doesn't access or modify any global state.
For the rest, you need more error checking on the input (did the open
succeed, etc.), and you really should be using std::vector, rather
than a C style array. (There are cases where C style arrays are
appropriate, but this isn't one of them.)
More fundamentally, I'd suggest you get a good book and study it. (I'd
recommend Stroustrup's Programming Principles and Practice Using C++.)
You can't write a program in any language without knowing at least the
most basic fundamentals and basic syntax.
you can pass it as pointers also