maintaining pair of elemts using own class template - c++

I made my own class template to maintain pair of elements of any type of objects. Now I am going to use this template for another own class MyPoint. this contain 3D cordinates of a point. I think I need to modify this further as my final objective is to use this PairInfor<MyPoint> as a vector<PairInfor<MyPoint> > and again vector<vector<PairInfor<MyPoint> > >. SO, I need your support to modify this as I do not have very knowledge to prepare this types of templates.
I got assistant from some other classes and books, but i need to include most common functions to this. Can anyone help please?
Here is my template class;
// class to accomadate two values
//-------------------------------
#include <stdlib.h>
#include <iostream>
template <class Type>
class PairInfor {
private:
/// two elements of the pair
Type x[2];
public:
// Default constructor.
PairInfor() { x[0] = x[1] = -1; }
// other Constructors.
PairInfor(Type xv, Type yv) {
x[0] = xv; x[1] = yv;
}
PairInfor(const Type *v) { x[0] = v[0]; x[1] = v[1]; }
//constructor for Coping
PairInfor(const PairInfor &v) { x[0] = v.x[0]; x[1] = v.x[1]; }
// Destructor.
~PairInfor() {}
// assignament
PairInfor& operator=(const PairInfor &v)
{ x[0] = v.x[0]; x[1] = v.x[1];
return *this;
}
// Element access, for getting.
Type V1() const { return x[0]; }
// Element access, for getting.
Type V2() const { return x[1]; }
// Element access, for getting.
Type operator[] (int i) const { return x[i]; }
// Element access, for writing.
Type &V1() { return x[0]; }
// Element access, for writing.
Type &V2() { return x[1]; }
// Element access, for writing.
Type &operator[] (int i) { return x[i]; }
// Return a constant reference to the pair
const class PairInfor &infor() const { return *this; }
// Return a reference to the pair
PairInfor &infor() { return *this; }
// comparing two pair packets
friend bool operator == (const PairInfor &v1, const PairInfor &v2)
{
return v1.x[0] == v2.x[0] && v1.x[1] == v2.x[1];
}
};
When I use this template class, I get the following error too.
\include\PairInfor.hpp In constructor `PairInfor<Type>::PairInfor() [with Type = MyPoint]':
\myprogf.cpp instantiated from here
\include\PairInfor.hpp invalid conversion from `int' to `char*'
\include\PairInfor.hpp initializing argument 1 of `MyPoint::MyPoint(char*)'
\Makefile.win [Build Error] [myprogf.o] Error 1
How do I solve this error. Is the error with my default constructor in PairInfor. How do I solve this please?
Thanks in advance.

The following line doesn't work for any type:
PairInfor() { x[0] = x[1] = -1; }
You are trying to assign an integer, but Type may not support that. MyPoint doesn't, hence the error.
You should default-initialize your members:
PairInfor() : x() {}
Note that std::pair might cover your needs already.

Related

Struct with array that changes dynamically

I have been looking to change dynamically the values of an array in a struct depending on other variables of the struct.
Let's say I have:
struct foo
{
int value1 = 0;
int value2 = 0;
int arr[2] = {value1, value2};
};
In the main if I have create an instance fooInstance and I want to associate a value to value1 fooInstance.value1 = 10, how can I update the value in the array ?
Thank you for your time.
Firstly, if you need an array, then I recommend storing the objects in the array directly.
I question the value (i.e. usefulness) of these aliases such as value1 when the name has no more meaning than referring to arr[i] directly. But I can see the value in case there is a descriptive name available. I'll use a more meaningful example of 2D vector with x, y dimensions. It should be easy to change float to int and change the names to match your attempt.
While Frank's solution using functions is great in most regards, it has a small caveat of having a less convenient syntax compared to variables. It's possible to achieve the variable syntax using operator overloading and anonymous unions. The trade-off is the increased boilerplate in the class definition. Example:
union Vector2 {
struct {
float a[2];
auto& operator=(float f) { a[0] = f; return *this; }
operator float&() & { return a[0]; }
operator const float&() const & { return a[0]; }
operator float () && { return a[0]; }
float* operator&() { return &a[0]; }
} x;
struct {
float a[2];
auto& operator=(float f) { a[1] = f; return *this; }
operator float&() & { return a[1]; }
operator const float&() const & { return a[1]; }
operator float () && { return a[1]; }
float* operator&() { return &a[1]; }
} y;
struct {
float a[2];
auto& operator=(float f) { a[0] = a[1] = f; return *this; }
float* begin() { return std::begin(a); }
float* end() { return std::end(a); }
} xy;
};
int main() {
Vector2 v2;
v2.xy = 1337; // assign many elements by name
v2.x = 42; // assign one element by name
std::cout << v2.x; // read one element by name
for(float f : v2.xy) { // iterate the entire array
std::cout << f;
}
}
Note to those unfamiliar with rules of unions: Reading from inactive union member is allowed only through common initial sequence of standard layout structs. This code is well defined, but the reader should be careful to not over generalise and assume that type punning through unions would be allowed; It isn't.
I adapted code from my earlier answer to another question.
It is different parameters coming from different hardwares.
This sounds like generating the accessors shown above with meta programming could be a good approach.
But, if you would like to avoid the complexity, then a more traditional approach would be to just use the array, and use enum to name the indices:
struct foo
{
int arr[100];
enum indices {
name1,
name2,
// ...
name100,
name_count,
};
};
int main()
{
foo f;
f.arr[foo.name1] = 42;
}
If at all possible, use encapsulation. That's the preferred way to create an interface/implementation skew:
struct foo
{
int& value1() { return arr_[0]; }
int& value2() { return arr_[1]; }
int* arr() { return arr_; }
private:
int arr_[2] = {0, 0};
};
void bar(foo& v) {
// access a single value
v.value1() = 3;
// access the whole array
v.arr()[0] = 5;
}
If you need access through both the individual member variables and through an array member variable, do not copy the data; rather, use the array as "the source of truth", and provide access through the individual variables or the individual member functions.
Here is your example rewritten to "alias" array variables to scalar member variables:
struct foo
{
foo() : value1(arr[0]), value2(arr[1]) {}
std::array<int,2> arr;
int& value1;
int& value2;
};
Note: this is not a good way of doing anything in production code, just an illustration of how the language lets you do something like this. Normally I would add accessor member-functions instead of member-variable references, because it avoids many problems referenced in the comments, such as breaking the value semantics.

How do I call template array operator overloading function?

I need to create an adapter C++ class, which accepts an integer index, and retrieves some types of data from a C module by the index, and then returns it to the C++ module.
The data retrieving functions in the C module are like:
int getInt(int index);
double getDouble(int index);
const char* getString(int index);
// ...and etc.
I want to implement an array-like interface for the C++ module, so I created the following class:
class Arguments {
public:
template<typename T> T operator[] (int index);
};
template<> int Arguments::operator[] (int index) { return getInt(index); }
template<> double Arguments::operator[] (int index) { return getdouble(index); }
template<> std::string Arguments::operator[] (int index) { return getString(index); }
(Template class doesn't help in this case, but only template member functions)
The adapter class is no biggie, but calling the Arguments::operator[] is a problem!
I found out that I can only call it in this way:
Arguments a;
int i = a.operator[]<int>(0); // OK
double d = a.operator[]<double>(1); // OK
int x = a[0]; // doesn't compile! it doesn't deduce.
But it looks like a joke, doesn't it?
If this is the case, I would rather create normal member functions, like template<T> T get(int index).
So here comes the question: if I create array-operator-overloading function T operator[]() and its specializations, is it possible to call it like accessing an array?
Thank you!
The simple answer is: No, not possible. You cannot overload a function based on its return type. See here for a similar quesiton: overload operator[] on return type
However, there is a trick that lets you deduce a type from the lhs of an assignment:
#include <iostream>
#include <type_traits>
struct container;
struct helper {
container& c;
size_t index;
template <typename T> operator T();
};
struct container {
helper operator[](size_t i){
return {*this,i};
}
template <typename T>
T get_value(size_t i){
if constexpr (std::is_same_v<T,int>) {
return 42;
} else {
return 0.42;
}
}
};
template <typename T>
helper::operator T(){
return c.get_value<T>(index);
}
int main() {
container c;
int x = c[0];
std::cout << x << "\n";
double y = c[1];
std::cout << y ;
}
Output is:
42
0.42
The line int x = c[0]; goes via container::get_value<int> where the int is deduced from the type of x. Similarly double y = c[1]; uses container::get_value<double> because y is double.
The price you pay is lots of boilerplate and using auto like this
auto x = c[1];
will get you a helper, not the desired value which might be a bit unexpected.

Overloading operator[] keeps throwing a runtime error

Alright, so I'm trying to create a Matrix class, and I really, really, want to be able to call elements by using brackets. In the style of mMatrix[x][y].
So I have a vector<vector<T>> member, and when overloading the [] operator, I return a reference to a vector<T> object.
template<class T>
class Matrix
{
private:
uint32_t DimensionHorizontal;
uint32_t DimensionVertical;
std::vector<std::vector<T>> matrix;
public:
Matrix()
{
DimensionHorizontal = 10;
DimensionVertical = 10;
}
std::vector<T>& operator[] (int index)
{
return matrix.[index];
}
Matrix(int x, int y)
{
DimensionHorizontal = x;
DimensionVertical = y;
}
};
This seems to be working because when I create a Matrix object, and try to add an element by doing Matrix[a][n] (using integers in this case), it compiles without issues. I later try to print out the value stored there with cout.
During runtime, I get the following error
Expression: vector subscript out of range on Line 1455 of the vector.
On line 1455:
_NODISCARD size_type capacity() const noexcept { // return current length of allocated storage
auto& _My_data = _Mypair._Myval2;
return static_cast<size_type>(_My_data._Myend - _My_data._Myfirst);
}
_NODISCARD _Ty& operator[](const size_type _Pos) noexcept { // strengthened
auto& _My_data = _Mypair._Myval2;
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(
_Pos < static_cast<size_type>(_My_data._Mylast - _My_data._Myfirst), "vector subscript out of range");
#endif // _CONTAINER_DEBUG_LEVEL > 0
return _My_data._Myfirst[_Pos];
}
I am sort of confused about why this is happening. I know I'm trying to access something out of bounds, or doing something otherwise illegal, but Matrix[] should return a vector, and I should be able to use [] again to access the element T (in this case int), any help would be appreciated.
EDIT:
This is how I use the class
int main()
{
Matrix<int> a(10, 10);
a[0][0] = 10;
std::cout << a[0][0];
return 0;
}
You need to resize the matrix in your constructor to match the size passed as arguments.
Matrix(int x, int y) : matrix(x)
{
for( auto& sub : matrix ) {
sub.resize(y);
}
DimensionHorizontal = x;
DimensionVertical = y;
}

How to convert a custom vector<typename> to & from an STL vector<long> without changing given code?

I have this homework problem where I have to implement an interpreter for a made up programming language called GritVM.I have built the program and it works using the STL List and Vector as per required by the first question, but on part 2, an optional question asked me to implement my own vector template class and implement it on top of this GritVM.hpp & GritVM.cpp (orignal STL based implementation) without changing the function parameters or the data members I started with.
So far, I have made a custom vector class called ArrayVector. And have made all of the basic ADT vector using the array data structure. I am stuck on two places. My conversion from and to STL doesn't work. I was wondering if someone can help me out. I can provide more code, if you require more info. Thanks in advance.
Errors I am getting are:
GritVM.cpp: In member function 'virtual STATUS GritVM::load(std::__cxx11::string, const std::vector<long int>&)':
GritVM.cpp:56:14: error: binding 'const std::vector<long int>' to reference of type 'std::vector<long int>&' discards qualifiers
myDataMem = initialMemory;
^~~~~~~~~~~~~
In file included from GritVM.hpp:7:0:
ArrayVector.hpp:47:18: note: initializing argument 1 of 'ArrayVector<Object>& ArrayVector<Object>::operator=(std::vector<Object>&) [with Object = long int]'
ArrayVector& operator= (std::vector<Object>& stlv){
^~~~~~~~
ArrayVector.hpp: In instantiation of 'std::vector<Object>& ArrayVector<Object>::tempVec_to_stlVec() [with Object = long int]':
GritVM.cpp:17:37: required from here
ArrayVector.hpp:53:41: error: conversion from 'long int*' to non-scalar type 'std::vector<long int>' requested
std::vector<Object> to_stdVec = Arr;
^~~
ArrayVector.hpp:53:29: warning: reference to local variable 'to_stdVec' returned [-Wreturn-local-addr]
std::vector<Object> to_stdVec = Arr;
ArrayVector.hpp
/********ArrayVector.hpp template class************/
/*Base is given by the book author, it includes enum data
for instructions and machine code. I can give you the code for the base file too*/
#include "GritVMBase.hpp"
template<typename Object>
class ArrayVector{
private:
int capacity;
auto num_longElem;
Object* Arr;
protected:
public:
friend class GritVM;
ArrayVector() : capacity(0), num_longElem(0), Arr(nullptr) { }
ArrayVector(std::vector<Object>& stl_vector_para){
Arr = stl_vector_para;
capacity = stl_vector_para.capacity();
num_longElem = stl_vector_para.size();
};
~ArrayVector(){
delete [] Arr;
}
ArrayVector(const ArrayVector& av){
capacity = av.capacity;
num_longElem = av.num_longElem;
Arr = new Object [capacity];
for(auto x = 0; x < num_longElem; ++x){
Arr[x] = av.Arr[x];
}
}
ArrayVector& operator= (ArrayVector& av){
ArrayVector copy = av;
std::swap(*this, copy);
return *this;
}
/***********NOT SURE ABOUT THESE TWO!!!*************/
ArrayVector& operator= (std::vector<Object>& stlv){
ArrayVector copy = stlv;
std::swap(*this, copy);
return *this;
}
std::vector<Object>& tempVec_to_stlVec(ArrayVector& av){
std::vector<Object> to_stdVec = av;
return to_stdVec;
}
/***************************************************/
Object& at(auto index){
if(index < 0 || index > num_longElem){
throw ("Out of bound access.\n");
}
return Arr[index];
}
void erase(auto index){
if(index < 0 || index > num_longElem){
throw ("erase() failed.\n");
}
for(auto x = index + 1; x < num_longElem; ++x){
Arr[x-1] = Arr[x];
}
--num_longElem;
}
void insert(auto index, const Object& le){
if(num_longElem >= capacity){
reserve(std::max(1 , 2*capacity));
}
for(auto x = num_longElem-1; x >= index; --x){
Arr[x+1] = Arr[x];
}
Arr[index] = le;
++num_longElem;
}
/*...then some more basic ADT like size(), empty(), reserve(), empty() etc...*/
};
GritVM.hpp
#include "ArrayVector.hpp"
#include "GritVMBase.hpp"
class GritVM : public GritVMInterface {
private:
long accumulator; /*Stores the result*/
STATUS machineStatus; /*Gets the enum data from Machine Status*/
std::list<Instruction>::iterator currentInstruct; /*Iterator that runs on enum data*/
std::list<Instruction> instructMem;/*Adds the instruction*/
std::vector<long> dataMem; /*Data memory, can't be erased or changed*/
ArrayVector<long> myDataMem; /*TRYING TO GET THIS IMPLEMENTED ALONG SIDE STL VECTOR dataMem*/
long evaluate(Instruction current_instruction); /*Does arithmatic based on instruction*/
void advance(long move_instruction_amount); /*Advances the machine instruction*/
protected:
public:
GritVM(); /*Default constructor*/
~GritVM() { } /* Default destructor*/
/*Assignment realated overridden functions, were pure virtial functions, the parameters can't be changed*/
STATUS load(const std::string filename, const std::vector<long>& initialMemory);
STATUS run();
std::vector<long> getDataMem();
STATUS reset();
};
GritVM.cpp
#include "GritVM.hpp"
GritVM::GritVM() : accumulator(0), machineStatus(WAITING) { }/*Default constructor*/
/*Resets the machine state to default*/
STATUS GritVM::reset() {
accumulator = 0;
machineStatus = WAITING;
//dataMem.clear();
myDataMem.clear(); /**>>>>>HERE<<<<<**/
instructMem.clear();
return machineStatus;
}
/*Returns the current data in the Data Memory*/ /**>>>>>HERE<<<<<**/
std::vector<long> GritVM::getDataMem() {
//return dataMem;
return myDataMem.tempVec_to_stlVec(myDataMem);
}
STATUS GritVM::load(const std::string filename, const std::vector<long>& initialMemory) {
/**Taken away some reading from gvm file to save room***/
/*Copy the memory to data vector*/
//dataMem = initialMemory;
myDataMem= initialMemory; /**>>>>>HERE<<<<<**/
return machineStatus;
}
/*Run instruction for the Grit machine*/
STATUS GritVM::run() {
/***Taken away to save room, is not related to dataMem vector***/
return machineStatus;
}
/*All these evaluate came from the table in the book */
long GritVM::evaluate(Instruction current_instruction) {
long move_instruction_amount = 0; /*Instruction move counter*/
/*******SOME OF THE dataMem are here*******/
switch (current_instruction.operation) {
case AT:
machineStatus = RUNNING;
move_instruction_amount = 1;
//accumulator = dataMem.at(current_instruction.argument);
accumulator = myDataMem.at(current_instruction.argument);
break; /**>>>>>HERE<<<<<**/
case SET:
machineStatus = RUNNING;
move_instruction_amount = 1;
//dataMem.at(current_instruction.argument) = accumulator;
myDataMem.at(current_instruction.argument) = accumulator;
break; /**>>>>>HERE<<<<<**/
case INSERT:
machineStatus = RUNNING;
move_instruction_amount = 1;
//dataMem.insert(current_instruction.argument, accumulator);
myDataMem.insert(current_instruction.argument, accumulator);
break; /**>>>>>HERE<<<<<**/
/***a lot of cases are taken out***/
default:
machineStatus = ERRORED;
break;
}
return move_instruction_amount;
}
/*Takes the instruction, and advancces its amount, given from the pdf file*/
void GritVM::advance(long move_instruction_amount) {
/***taken away to save room, doesn't use dataMem vector****/
}
First off I would recommend not implementing your own vector. There is a lot of pitfalls and it's complicated to do it right.
There are many problems that prevents the conversion to happen.
First, your operator= takes a mutable reference to a vector:
// not const -------v
ArrayVector& operator= (std::vector<Object>& stlv){
ArrayVector copy = stlv;
std::swap(*this, copy);
return *this;
}
// v------- not const either
ArrayVector(std::vector<Object>& stl_vector_para){
Arr = stl_vector_para;
capacity = stl_vector_para.capacity();
num_longElem = stl_vector_para.size();
}
Mutable reference are taken, but you don't need to actually mutate the vector. Making them const will fix the first problem, since you are trying to pass a const vector to it:
// a reference to a const vector ---v
STATUS load(const std::string filename, const std::vector<long>& initialMemory) {
myDataMem = initialMemory;
// ^----- cannot pass a const vector to a
// function that takes a mutable one
return machineStatus;
}
Then, you have a lifetime issue:
// returns by reference
std::vector<Object>& tempVec_to_stlVec(ArrayVector& av) {
// to_stdVec lives until the end of the function
std::vector<Object> to_stdVec = av;
return to_stdVec; // return a reference to an object that will die
}
Local variable don't live past their scopes. You are returning a reference to a dead vector. Simply return by value instead:
// by value
std::vector<Object> tempVec_to_stlVec(ArrayVector& av) {
// to_stdVec lives until the end of the function
std::vector<Object> to_stdVec = av;
return to_stdVec; // return the object by value
}
Return value optimisation will take care of making the return by value efficient. If that optimisation cannot be done, move constructor will take care of it.
Then I saw errors that wasn't in the posted errors.
Vectors are not convertible into pointers:
Arr = stl_vector_para;
It doesn't work that way. If you really want to make your own vector class, you must do dynamic allocations and copy data into, manually.
C++ offers these data structure for a reason: to make our life easier, and make C++ enjoyable. Implementing your own vector is usually pain unless you know what you are doing.

problem with `==` operator

There is some class wComplex with == operator.
#ifndef WCOMPLEX_H
#define WCOMPLEX_H
#include <stdio.h>
// sample class of complex-like numbers with weird `==` operator
class wComplex{
private:
double realPart;
double imagePart;
public:
wComplex();
wComplex(double R);
wComplex(double R, double I);
bool operator==(wComplex &);
void print();
};
wComplex::wComplex(){
realPart = 0;
imagePart = 0;
}
wComplex::wComplex(double R){
realPart = R;
imagePart = 0;
}
wComplex::wComplex(double R, double I)
{
realPart = R;
imagePart = I;
}
bool wComplex::operator==(wComplex &El){
double diff = realPart*realPart + imagePart*imagePart -
El.realPart*El.realPart - El.imagePart*El.imagePart;
return (diff == 0);
}
void wComplex::print(){
printf("(%g) + (%g)i\n", realPart, imagePart);
}
#endif
It successfully worked with stuff like that:
wComplex A(1, 2);
wComplex B(2, 4);
wComplex C(2, 1);
(A==C) is true.
There is another class - queue-like. But it should control the new pushed element for equality (in == meaning) of other elements.
#ifndef MYQueue_H
#define MYQueue_H
#include <stdio.h>
#include <queue>
template<typename T>
class myQueue : public std::queue<T>{
public:
myQueue(){
printf("new myQueue successfully created\n");
}
void push (const T& x){
myQueue* tmp = new myQueue;
myQueue* old = new myQueue;
old = this;
bool MATCH = false;
while(!old->empty()){
T el = old->front();
if(el == x){
MATCH = true;
tmp->push(x);
}
else
tmp->push(el);
old->pop();
}
if(!MATCH)
tmp->push(x);
this = *tmp;
delete tmp;
delete old;
}
};
#endif
So, now there is one problem
myqueue.h: In member function ‘void myQueue<T>::push(const T&) [with T = wComplex]’:
shit.cpp:23: instantiated from here
myqueue.h:26: error: no match for ‘operator==’ in ‘el == x’
wcomplex.h:36: note: candidates are: bool wComplex::operator==(wComplex&)
myqueue.h:36: error: lvalue required as left operand of assignment
make: *** [compile] Error 1
Actually, I can't understand why no match for ‘operator==’ in ‘el == x’
And what should I do? Any ideas
UPD: and how can I replace this element by tmp?
It's something wrong with this = *tmp;
You have a const reference to T in push() but your operator== only accepts non-const references.
bool wComplex::operator==(wComplex &El)
should be
bool wComplex::operator==(wComplex const &El) const
Or, optimally, your operator== should be a free function:
bool operator==(wComplex const & Left, wComplex const & Right) {
}
If you don't want outside access to the member variables of wComplex, you'll need to make the operator a friend function:
class wComplex {
...
friend bool operator==(wComplex const & Left, wComplex const & Right);
...
};
EDIT: On the updated question:
You cannot assign to this. this is of type T * const - since it wouldn't make sense to modify it. What you're trying to do is to change an external variable which points to the current class, you cannot do that from inside a class member function unless this external variable is passed in as an argument.
I think you need to make a "queue" class which manages "node" class instances - trying to combine a container and the contained elements isn't really a good idea
Also, inheriting standard library containers is rarely a good idea. If you want to use a std::queue then make a member variable.
Change:
bool wComplex::operator==(wComplex &El){
into:
bool wComplex::operator==(const wComplex &El) const {
One tips for the future:
The const keyword, either you put it nowhere, or everywhere you can.
Obviously, everywhere you can is better.