I am doing a c++ program. Here's what I have to do: I create an array of the size I want. The array is auto-filled with 0.
With the operator += i have to insert 1 at the place i chose.
Example :
array += 2;
will insert 1 at the index 2 of my array.
But how can I do it ?
My .h file
#ifndef BITARRAY_H
#define BITARRAY_H
#include <ostream>
class bitArray
{
public:
bitArray(int n);
virtual ~bitArray();
bitArray& operator+=(const bitArray&); //this operator
bitArray& operator-=(const bitArray&);
int& operator[] (int x) {
return sortie[x];
}
protected:
private:
int sortie[];
int n;
};
//ostream& operator<<(ostream&, const bitArray&);
#endif // BITARRAY_H
My method in the cpp file :
bitArray& bitArray::operator+=(const bitArray& i)
{
this ->sortie[i] = 1;
return *this;
}
But it does not work. Am I doing the right way?
My error is :
no match for 'operator[]' (operand types are 'int [0]' and 'const bitArray')|
Thank you in advance !
no match for operator[] (operand types are 'int [0]' and 'const
bitArray')|
The error is crystal clear that the operator[] expecting an interger type and what you passing a bitArray class type. Simple fix is to change it to integer.
However, here:
private:
int sortie[];
int n;
it is highly recommended to use std::vector, which gives a contiguous dynamic array whereas sortie[]is static allocation. Something like this:
See live here
#include <iostream>
#include <vector>
#include <cstddef>
class bitArray
{
private:
std::vector<int> sortie;
public:
explicit bitArray(int size): sortie(size) {}
bitArray& operator+=(const std::size_t i)
{
if (0 <= i && i < sortie.size()) // check for (0 <= index < size) of the array
{
this ->sortie[i] = 1;
return *this;
}
else
{
// do your logic! for instance, I have done something like follows:
std::cout << "out of bound" << std::endl;
if(sortie.size() == 0) sortie.resize(1,0); // if the size of array == 0
}
return *this;
}
int operator[] (const std::size_t index)
{
return (0 <= index && index < sortie.size()) ? sortie[index] : -1;
}
};
int main ()
{
bitArray obj(3);
obj += 0; std::cout << obj[0] << std::endl;
obj += -2; std::cout << obj[-2] << std::endl;
obj += 22; std::cout << obj[22] << std::endl;
return 0;
}
Update: Using C++17 feature std::optional, modified the above solution with the optional return type, which should be more readable.
See output in wandbox
#include <iostream>
#include <vector>
#include <cstddef>
#include <optional>
class bitArray
{
private:
std::vector<int> sortie;
public:
explicit bitArray(int size): sortie(size) {}
// optional is used as the return type
std::optional<bitArray> operator+=(const std::size_t i)
{
if (i < sortie.size()) // check for (0 <= index < size) of the array
{
this -> sortie[i] = 1;
return std::optional<bitArray>{*this};
}
std::cout << "out of bound operation+= \t";
return std::nullopt; // std::nullopt to create any (empty) std::optional
}
std::optional<int> operator[] (const std::size_t index)
{
if(index < sortie.size()) return std::optional<int>{sortie[index]};
else
{
std::cout << "out of bound operator[]: ";
return std::nullopt;
}
}
};
int main ()
{
bitArray obj(3);
obj += 0; std::cout << obj[0].value_or(-1) << std::endl;
obj += -2; std::cout << obj[-2].value_or(-1) << std::endl;
bitArray obj1(0);
obj1 += 22; std::cout << obj1[22].value_or(-1) << std::endl;
return 0;
}
Your operator+= takes a bitArray as parameter, but it should take the index where to set the 1 and thats basically what the error message is trying to tell you: There is no overload for the parameters you are trying to use it.
Note that to get such an operator you dont need to write your own array class, but you can provide an overload for std::vector:
#include <iostream>
#include <vector>
template <typename T>
std::vector<T>& operator+=(std::vector<T>& v,size_t index) {
v[index] = 1;
return v;
}
int main() {
auto vec = std::vector<int>(10,0);
vec += 5;
std::cout << vec[5];
return 0;
}
Note that this is a rather uncommon way to implement += (it does not really add anything). I would consider this as misuse of operator overloading and it will lead to obfuscated code. Consider this:
vec[5] = 1;
vs
vec += 5;
In the first line, everybody who is familiar with std::vector will know what it does, while for the second line 90% of the expectations will be off. I guess you are doing this as part of an assignment or homework, though for anything else I would suggest you to stay away from using operator overloads that do anything more than the obvious thing.
Related
As an old c99 person, I was often stubled upon the curly brakets initialization. In the `initializer_list`, I have to use {r, i} for a complex number. On the other hand, I have to use (r, i) for `complex` in the istream field. Here, I cut a part of my class that is able to run and give examples under codeblock 20.03 with MinGW 8.1.0.
#ifndef __tMatrix_class__
#define __tMatrix_class__
#include <iostream>
#include <initializer_list>
#include <iomanip>
#include <complex>
#include <sstream>
template <typename T> class tMatrix
{
public:
T *ptr;
int col, row, size;
inline T* begin() const {return ptr;}
inline T* end() const {return this->ptr + this->size;}
inline T operator()(const int i, const int j) const { return ptr[i*col+j]; } // r-value
inline T&operator()(const int i, const int j) { return ptr[i*col+j]; } //l-value
inline tMatrix(): col{0}, row{0}, size{0}, ptr{0} {;}
tMatrix(const int i, const int j): col(j), row(i), size(i*j) {
ptr = new T [this->size] ; }
tMatrix(const std::initializer_list< std::initializer_list<T> > s):tMatrix<T>(s.size(), s.begin()->size())
{
int j = 0;
for (const auto& i : s) { std::copy (i.begin(), i.end(), ptr + j*col); ++j ; }
}
tMatrix(const tMatrix<T>&a) : tMatrix<T>(a.row, a.col)
{
std::copy(a.begin(), a.end(), this->ptr);
}
tMatrix<T>& operator=(tMatrix<T>&&a)
{
this->col = a.col;
this->row = a.row;
delete [] this->ptr;
this->ptr = a.ptr;
a.ptr = nullptr;
return *this;
}
tMatrix<T>& operator=(const tMatrix<T>&a)
{
if (col==a.cpl && row==a.row) std::copy(a.begin(), a.end(), this->ptr);
else { tMatrix<T>&&v(a); *this = std::move(v);}
return *this;
}
tMatrix<T>& operator=(const std::initializer_list<std::initializer_list<T> > a)
{
tMatrix<T> &&v = a;
*this = std::move(v);
return *this;
}
~tMatrix() {delete [] this->ptr;}
void operator<<(const char*s)
{
std::stringstream ss;
ss.str(s);
for (int i=0; i<this->size; i++){
if (ss.good()) ss >> this->ptr[i];
else return;
}
}
}; //end of class tMatrix
template <typename X> std::ostream& operator<<(std::ostream&p, const tMatrix<X>&a)
{
p << std::fixed;
for (int i=0; i<a.row; i++) {
for (int j=0; j <a.col; j++) p << std::setw(12) << a(i, j);
p << std::endl;
}
return p;
}
using CMPLX = std::complex<double>;
using iMatrix = tMatrix<int>;
using rMatrix = tMatrix<double>;
using cMatrix = tMatrix< CMPLX >;
#endif
int main()
{
cMatrix cx(2,2);
cx = { { {1,2},{3,4} }, { {5,6}, {7,8} } };
std::cout << cx << std::endl;
cx << "(1,2) (3,4)";
std::cout << cx << std::endl;
return 0;
}
The above code renders correct format of complex number, and prints
$ ./ttt_mtx_init_fin_tmp.exe
(1.000000,2.000000)(3.000000,4.000000)
(5.000000,6.000000)(7.000000,8.000000)
(1.000000,2.000000)(3.000000,4.000000)
(5.000000,6.000000)(7.000000,8.000000)
But if I use the `()` in the initializer_list and `{}` in the istream filed, the results are all wrong. If I chagned the relavant part of main() to :
cx = { { (1,2),(3,4) }, { (5,6), (7,8) } };
std::cout << cx << std::endl;
cx << "{1,2} {3,4}";
std::cout << cx << std::endl;
Which renders all wrong values (compared with above):
$ ./ttt_mtx_init_fin_tmp.exe
(2.000000,0.000000)(4.000000,0.000000)
(6.000000,0.000000)(8.000000,0.000000)
(2.000000,0.000000)(4.000000,0.000000)
(6.000000,0.000000)(8.000000,0.000000)
I found it is rather confusion. So, my questions: is there a way to make these two expressions a same form? Many thanks for any helps.
I do not know any way to make std::istream::operator>> use { and } for std::complex, but if you are fine with using a helper, then you can replace the () in the input with {} and forward the input to the original operator>>:
#include <iostream>
#include <complex>
#include <sstream>
#include <algorithm>
template <typename T>
struct complex_reader {
std::complex<T>& target;
};
template <typename T>
complex_reader<typename T::value_type> get_complex_reader(T& t){ return {t};}
template <typename T>
std::istream& operator>>(std::istream& in,complex_reader<T> cr){
std::string input;
std::getline(in,input,'}'); // read till `}`
std::replace(input.begin(),input.end(),'{','(');
input += ')';
std::stringstream ss{input};
ss >> cr.target; // call the original >>
return in;
}
int main()
{
std::stringstream ss{"{2,2}"};
std::complex<double> x;
ss >> get_complex_reader(x);
std::cout << x;
}
Output:
(2,2)
However, you would have to write a similar helper to get consistent output (you may not provide an operator<< for std::complex<T> directly). Also note that the above implementation is a little simplistic. It reads from the stream until it encounters a }. For invalid input this may result in undesired effects and more sophisticated input validation is required.
Note that the operator>> takes the complex_helper by value to allow passing temporaries. Thats fine, because the member is a (non-const) reference.
This is not an answer, but a reasoning of my choice. After a series of cross conversions with `largest_prime_is_463035818`, I figured out what is my best choice for now (many thanks to his time and patience). A bottom line is becoming clear to me that I will not alter the input format of istream that is too much changed for pratical purpose, since file input is the major method to fetch data for a large matrix.
Under this constrain, I try to make the appearance of initializer_list as friendly as possible. I did some experiments, and found that the complex_literals expression is acceptable by initializer_list. And it looks ok to me.
using namespace std::complex_literals;
int main()
{
cMatrix cx(3,2);
cx = { { 1+2.2j , 4j}, { 5.3+6.5j , 8.3j}, {8.3, 5.6+4j} };
std::cout << cx << std::endl;
cx << " (1,2) (3,4) (5,6) (7,8) (2.3, 3.4) (2,7.8) ";
std::cout << cx << std::endl;
return 0;
}
And it works.
$ ./a.exe
(1.000000,2.200000) (0.000000,4.000000)
(5.300000,6.500000) (0.000000,8.300000)
(8.300000,0.000000) (5.600000,4.000000)
(1.000000,2.000000) (3.000000,4.000000)
(5.000000,6.000000) (7.000000,8.000000)
(2.300000,3.400000) (2.000000,7.800000)
Thank you for your patience, and please let me know if there are better ways.
I was trying to make a function that assigns y to x regardless whether x, y are int or std::string. I wrote this code:
#include <iostream>
#include <string>
#include <typeinfo>
template <typename T>
T& assign(T& x, T& y){
if ( typeid(x).name() == "Ss" && typeid(y).name() == "Ss" ){
std::string k = static_cast<std::string>(y);
x = k;
return x;
}
else if ( typeid(x).name() == "i" && typeid(y).name() == "i" ){
int k = static_cast<int>(y);
x = k;
return x;
}
else{
std::cout << "uncorrect assignment" << std::endl;
}
}
int main(){
std::string a = "empty_string";
std::string b = "Hi there";
assign(a, b);
std::cout << a << std::endl;
}
But it doesn’t work.
It gives the error:
[Error] invalid static_cast from type ‘std::basic_string<char>’ to type
at line 14:
int k = static_cast<int>(y);
I can’t understand, what is the problem?
I know the objection: I might have just defined function assign as:
template <typename T>
T& assign(T& x, T& y){
x = y;
}
which works. However, I was working on an other more complex function on which I have to (or at least I haven’t found any way other than) use static_cast.
So, if you could, please, explain to me what is the mistake in this example, I may try to fix the function I am working on.
Thank you very much,
Simone.
To do what do you want, you need C++17 and if constexpr. And the use of something that works compile-time, not of typeid that works runtime.
The problem is that with your code, typeid permit, runtime, to choose the if or the else part of your code, but the compiler must compile both part. So must compile
int k = static_cast<int>(y);
x = k;
when T is std::string. This give an error.
You need a type-traits (std::is_same, by example), that is evaluated compile-time, and a construct that avoid the compilation of the wrong part. This construct is if constexpr ( <test> ) (where the <test> is valuable compile time) but, unfortunately, is available only from C++17.
So, in C++17 you can write
template <typename T>
void assign (T & x, T const & y)
{
if constexpr ( std::is_same<T, std::string>::value ) {
std::string k = static_cast<std::string>(y);
x = k;
}
else if constexpr ( std::is_same<T, int>::value ) {
int k = static_cast<int>(y);
x = k;
}
else {
std::cout << "uncorrect assignment" << std::endl;
}
}
but, pre C++17, you have to follows different ways.
To handle different types separately inside a function, an option is to define a local struct with overloaded function call operators to different types:
#include <iostream>
#include <string>
template<typename T>
T& assign(T& x, const T& y) {
struct {
void operator()(std::string& lhs, const std::string& rhs) {
std::cout << "Type is std::string." << std::endl;
lhs = rhs;
}
void operator()(int& lhs, const int& rhs) {
std::cout << "Type is int." << std::endl;
lhs = rhs;
}
} assign_impl;
assign_impl(x, y);
return x;
}
int main() {
/* Test No. 1 */ {
std::string dest, src = "Foo";
std::cout << "Test result: " << assign(dest, src) << std::endl;
}
/* Test No. 2 */ {
int dest, src = 32;
std::cout << "Test result: " << assign(dest, src) << std::endl;
}
}
The code above will work on C++98 and above but its disadvantage is that it will raise compiler errors if you try to use it with unhandled types.
I have a vector. What I want to do is store a value at the first index of the vector. However, this value is for errors and so I would like to refer to this value like vector_ [-1]. How do I go about with this?
I came up with one solution.
What I'm doing is creating a new vector and assigning the new vector to this vector.
vector_.resize(required_size+1);
vector_ = std::vector<T> (vector_.begin()+1,vector_.end());
At this point could I legally use vector_[-1]? If not, please help me with other solutions.
EDIT
I found a workaround. Though its not vectors with negative indexing, I'm using a pointer to the second member of the vector so when I do ptr[-1], it points to the first element of the vector.
Here's the basic starting point of a vector where you can specify the (signed) lower and upper indexes
#include <vector>
#include <cassert>
#include <iostream>
#include <iomanip>
template<class T>
struct any_index_vector
{
any_index_vector(int min, int max)
: _zero_index(min)
, _storage((max - min))
{
// assert min - max
}
T& operator[](int index)
{
assert(index >= lower_limit());
assert(index <= upper_limit());
return _storage[index - _zero_index];
}
T& operator[](int index) const
{
assert(index >= lower_limit());
assert(index <= upper_limit());
return _storage[index - _zero_index];
}
int upper_limit() const {
return _zero_index + int(_storage.size());
}
int lower_limit() const {
return _zero_index;
}
int extent() const {
return upper_limit() - lower_limit();
}
int _zero_index = 0;
std::vector<T> _storage {};
};
int main()
{
any_index_vector<int> v(-1, 9);
for (int i = -1 ; i < 10 ; ++i) {
v[i] = (i+6);
}
for (int i = -1 ; i < 10 ; ++i) {
std::cout << "position: " << std::setw(2) << i << " : " << v[i] << std::endl;
}
}
expected output:
position: -1 : 5
position: 0 : 6
position: 1 : 7
position: 2 : 8
position: 3 : 9
position: 4 : 10
position: 5 : 11
position: 6 : 12
position: 7 : 13
position: 8 : 14
position: 9 : 15
You can not have negative indices in c++-standard-library, unless of course you provide your own class of a vector that decays that.
For, example check the ref:
Prototype: reference operator[] (size_type n);
Parameters: n Position
of an element in the container. Notice that the first element has a
position of 0 (not 1). Member type size_type is an unsigned integral
type.
Here is a class that could do what you want:
// Example program
#include <iostream>
#include <string>
#include <vector>
class myVector {
public:
int get(int index) { return v[index + 1]; }
void push_back(int value) { v.push_back(value); }
void print() {
for(unsigned int i = 0; i < v.size(); ++i)
std::cout << v[i] << " ";
std::cout << "\n";
}
const int& operator[](int index) const { return v[index + 1]; }
private:
std::vector<int> v;
};
int main() {
myVector v;
v.push_back(404); // error code
v.push_back(32); // real data
v.print();
std::cout << v[-1] << std::endl;
std::cout << v.get(-1) << std::endl;
return 0;
}
Output (Live Demo):
404 32
404
404
Since you are new to C++, operator overloading might puzzle you, skip it for now and come back later and read Operator overloading.
I dont understand why you want to do this. You could as well store the extra value in the first element and access it via vector_[0]. However, if you insist on using -1 as index, then I see only one proper way to do this:
template<typename T>
class {
public:
T& operator[](int index){
if (index==-1) { return value; }
else { return vector[index]; }
}
private:
T value;
std::vector<T> vector;
}
However, I would strongly suggest not to start something like this. You will waste lots of code just to get something that acts similar to a vector while you could simply use a plain std::vector and forget about the -1 indexing.
Similar Question is available here: How do I sort a vector of pairs based on the second element of the pair? but I am interested in External Memory Sorting.
I have tried using the analogies from Internal Memory Sorting but the error occurs in sorter_stream.h file of STXXL as:
My code :
#include <iostream>
#include <stxxl/vector>
#include <stxxl/sorter>
#include <limits>
using namespace std;
typedef std::pair<int,int> my_pair;
struct my_comparator
{
bool operator()(const my_pair& left, const my_pair& right)
{
return left.first < right.first;
}
int min_value() const
{
return std::numeric_limits<int>::min();
}
int max_value() const
{
return std::numeric_limits<int>::max();
}
};
int main()
{
typedef stxxl::sorter<my_pair, my_comparator> sorter_type;
sorter_type int_sorter(my_comparator(), 64 * 1024 * 1024);
for (int i = 10; i > 0; i--)
{
int_sorter.push(my_pair(i,i+10));
}
int_sorter.sort(); // sort elements (in ascending order)
while (!int_sorter.empty())
{
std::cout << (*int_sorter).first << " "<<(*int_sorter).second<<endl;
++int_sorter;
}
return 0;
}
Error :
sort_stream.h(481): error C2679: binary '=' : no operator found which takes a right-hand operand of type 'int' (or there is no acceptable conversion)
UPDATE:
Changing the return type of min_value(),max_value() function to my_pair as:
struct my_comparator
{
bool operator()(const my_pair& left, const my_pair& right)
{
return left.first < right.first;
}
my_pair min_value() const
{
return my_pair(std::numeric_limits<int>::min(),std::numeric_limits<int>::min());
}
my_pair max_value() const
{
return my_pair(std::numeric_limits<int>::max(),std::numeric_limits<int>::max());
}
};
gives the following Error:
sort_helper.h(94): error C3848: expression having type 'const my_comparator' would lose some const-volatile qualifiers in order to call 'bool my_comparator::operator ()(const my_pair &,const my_pair &)'
P.S. : Being a novice (Reputation<50) , I am not allowed to comment, that's why writing a new Question.
Got the following example in STXXL:Sorter Section which addresses the same problem.
Code:
#include <stxxl/sorter>
#include <stxxl/stats>
#include <stxxl/timer>
#include <stxxl/random>
#include <limits>
struct TwoInteger
{
int i, j;
TwoInteger()
{ }
TwoInteger(int _i, int _j)
: i(_i), j(_j)
{ }
};
struct TwoIntegerComparator
{
bool operator () (const TwoInteger& a, const TwoInteger& b) const
{
return a.i < b.i;
}
TwoInteger min_value() const
{
return TwoInteger(std::numeric_limits<int>::min(), std::numeric_limits<int>::min());
}
TwoInteger max_value() const
{
return TwoInteger(std::numeric_limits<int>::max(), std::numeric_limits<int>::max());
}
};
int main()
{
// template parameter <ValueType, CompareType, BlockSize(optional), AllocStr(optional)>
typedef stxxl::sorter<TwoInteger, TwoIntegerComparator, 1*1024*1024> sorter_type;
// create sorter object (CompareType(), MainMemoryLimit)
sorter_type int_sorter(TwoIntegerComparator(), 64 * 1024 * 1024);
stxxl::random_number32 rand32;
stxxl::timer Timer1;
Timer1.start();
// insert random numbers from [0,100000)
for (size_t i = 0; i < 1000; ++i)
{
int_sorter.push(TwoInteger(rand32() % 100000, (int)i)); // fill sorter container
}
Timer1.stop();
STXXL_MSG("push time: " << (Timer1.mseconds() / 1000));
stxxl::timer Timer2;
Timer2.start();
int_sorter.sort(); // switch to output state and sort
Timer2.stop();
STXXL_MSG("sort time: " << (Timer2.mseconds() / 1000));
// echo sorted elements
while (!int_sorter.empty())
{
std::cout << int_sorter->i << " "; // access value
++int_sorter;
}
return 0;
}
Is it possible to create an STL-like container, or even just an STL-style iterator, for an existing array of POD-type elements?
For example, suppose I have an array of ints. It would be convenient to be able to call some of the STL functions, such as find_if, count_if, or sort directly on this array.
Non-solution: copying the entire array, or even just references to the elements. The goal is to be very memory- and time-saving while hopefully allowing use of other STL algorithms.
You can call many of the STL algorithms directly on a regular C style array - they were designed for this to work. e.g.,:
int ary[100];
// init ...
std::sort(ary, ary+100); // sorts the array
std::find(ary, ary+100, pred); find some element
I think you'll find that most stuff works just as you would expect.
You can use an inline function template so that you don't have to duplicate the array index
template <typename T, int I>
inline T * array_begin (T (&t)[I])
{
return t;
}
template <typename T, int I>
inline T * array_end (T (&t)[I])
{
return t + I;
}
void foo ()
{
int array[100];
std::find (array_begin (array)
, array_end (array)
, 10);
}
All the STL algorithms use iterators.
A pointer is a valid iterator into an array of objects.
N.B.The end iterator must be one element past the end of the array. Hence the data+5 in the following code.
#include <algorithm>
#include <iostream>
#include <iterator>
int main()
{
int data[] = {4,3,7,5,8};
std::sort(data,data+5);
std::copy(data,data+5,std::ostream_iterator<int>(std::cout,"\t"));
}
You can use Boost.Array to create a C++ array type with STL semantics.
using arrays:
int a[100];
for (int i = 0; i < 100; ++i)
a[i] = 0;
using boost.arrays:
boost::array<int,100> a;
for (boost::array<int,100>::iterator i = a.begin(); i != a.end(); ++i)
*i = 0;
Update: With C++11, you can now use std::array.
A pointer is a valid model of an iterator:
struct Bob
{ int val; };
bool operator<(const Bob& lhs, const Bob& rhs)
{ return lhs.val < rhs.val; }
// let's do a reverse sort
bool pred(const Bob& lhs, const Bob& rhs)
{ return lhs.val > rhs.val; }
bool isBobNumberTwo(const Bob& bob) { return bob.val == 2; }
int main()
{
Bob bobs[4]; // ok, so we have 4 bobs!
const size_t size = sizeof(bobs)/sizeof(Bob);
bobs[0].val = 1; bobs[1].val = 4; bobs[2].val = 2; bobs[3].val = 3;
// sort using std::less<Bob> wich uses operator <
std::sort(bobs, bobs + size);
std::cout << bobs[0].val << std::endl;
std::cout << bobs[1].val << std::endl;
std::cout << bobs[2].val << std::endl;
std::cout << bobs[3].val << std::endl;
// sort using pred
std::sort(bobs, bobs + size, pred);
std::cout << bobs[0].val << std::endl;
std::cout << bobs[1].val << std::endl;
std::cout << bobs[2].val << std::endl;
std::cout << bobs[3].val << std::endl;
//Let's find Bob number 2
Bob* bob = std::find_if(bobs, bobs + size, isBobNumberTwo);
if (bob->val == 2)
std::cout << "Ok, found the right one!\n";
else
std::cout << "Whoops!\n";
return 0;
}