I am trying to make a program that demonstrates use of templates and overloaded operators for my CS class. Here is relevant code:
main:
ArrayTemplate<int> number(0);
number[0] = 1;
number[1] = 2;
number[2] = 3;
ArrayTemplate<string> word("na");
word[0] = "One";
word[1] = "Two";
word[2] = "Three";
header:
template<class T>
T& operator [](const int index)
{
if(index >= 0 && index < ARRAY_MAX_SIZE)
return items[index];
else
{
cerr << "INDEX OUT OF BOUNDS!!!";
exit(1);
}
}
The problem is that when I try to use my overloaded subscript operator I get the error message shown in title: "No such operator "[]" matches these operands" Im not exactly sure why. It does it for both my integer array and my string array. Any help is appreciated.
You really need to show the full definition of ArrayTemplate.
This is how you probably want it to look:
template<class T>
class ArrayTemplate {
public:
// ...
T& operator [](const int index)
{
if(index >= 0 && index < ARRAY_MAX_SIZE)
return items[index];
else
{
cerr << "INDEX OUT OF BOUNDS!!!";
exit(1);
}
}
// ...
};
Note that operator[] isn't templated; only the class is.
With your current code you would have to do it like this:
number<int>[0] = 1;
number<int>[1] = 2;
number<int>[2] = 3;
Which obviously goes against your intention.
template<class T>
T& operator [](const int index)
This declaration would be called e.g. as object.operator[] < type >( 5 ). Note that type needs to be provided as a template argument. Because there's no way to supply such an argument in an expression using [], the operator overload doesn't work.
Probably you don't want the template< class T > at all. Just get rid of it:
T& operator [](const int index)
If you define the function outside the class {} scope, then it would look like this:
template<class T>
T& ArrayTemplate<T>::operator [](const int index)
In this case, the template<class T> line re-introduces the parameter in order to get back into the class template.
Related
I am trying to implement linkedlist, and i have some problem with operator[]
template <class T>
T& L1List<T>::at(int i){
L1Item<T> * pRet = this->_pHead;
int idx = 0;
while(pRet){
if(i != idx){
pRet = pRet->pNext;
idx++;
}else return (pRet->data);
}
}
template <class T>
T& L1List<T>::operator[](int i){
return at(i);
}
and when i compile it, it runs with list->at(i), but list[i].
int a = list[i]; the error is that "cannot convert L1List'<'int> to ‘int’ in initialization"
If list->at(i) works, it means that list is a pointer, not an object. Hence, list[i] evaluates to an object. That's why int a = list[i]; does not work, which also explains the error message. You cannot use a L1List<int> to initialize an object of type int.
You need to use:
int a = (*list)[i];
or make it really complicated and use:
int a = list->operator[](i);
the Q is how to this kind of operator=
that it will work on:
int t = v[3]; // her i return by Value
v[3] = 8 ; // her i need to return by refrence (pointer to V[3] add')
will V is a Vector class (template class in my case)
template <class T>
T& Vector<T>::operator[](const int Index) const
{
if(Index > -1 && Index < this->Size)
{
return &this->Array[Index];
}
else
{
cerr <<"VECTOR_INVALID_INDEX"<<endl;
return NULL;
}
};
There are several errors in this example. this is already a pointer. Doing &this is almost certainly not what you meant to do here. The other problem you are having is that you are returning a reference to T but this is const in this context. this->Array[Index] is const T which cannot bind to T&. Add a const and return const T& instead. Thirdly, this->Size is not calling the method Size, you forgot parentheses. The fourth problem is a reference binding to NULL. You will have to decide on another approach. The usual way to indicate that an operation cannot be completed is to throw an exception. std::vector::at throws std::out_of_range from header stdexcept.
template <class T>
const T& Vector<T>::operator[](const int Index) const
//^^^ add const here
{
if (Index > -1 && Index < this->Size())
// Add parentheses ^^
{
return this->Array[Index];
// ^ No need for &
}
else
{
throw std::out_of_range("VECTOR_INVALID_INDEX");
}
};
You will probably want to add a non-const version as well, since this will fail for the example v[3] = 8;. Define this method as well with the same body :
T& Vector<T>::operator[](const int Index);
Quite often I have two variables foo1 and foo2 which are numeric types. They represent the bounds of something.
A user supplies values for them, but like a recalcitrant musician, not necessarily in the correct order!
So my code is littered with code like
if (foo2 < foo1){
std::swap(foo2, foo1);
}
Of course, this is an idiomatic sort with two elements not necessarily contiguous in memory. Which makes me wonder: is there a STL one-liner for this?
I suggest to take a step back and let the type system do the job for you: introduce a type like Bounds (or Interval) which takes care of the issue. Something like
template <typename T>
class Interval {
public:
Interval( T start, T end ) : m_start( start ), m_end( end ) {
if ( m_start > m_end ) {
std::swap( m_start, m_end );
}
}
const T &start() const { return m_start; }
const T &end() const { return m_end; }
private:
T m_start, m_end;
};
This not only centralizes the swap-to-sort code, it also helps asserting the correct order very early on so that you don't pass around two elements all the time, which means that you don't even need to check the order so often in the first place.
An alternative approach to avoid the issue is to express the boundaries as a pair of 'start value' and 'length' where the 'length' is an unsigned value.
No, but when you notice you wrote the same code twice it's time to write a function for it:
template<typename T, typename P = std::less<T>>
void swap_if(T& a, T& b, P p = P()) {
if (p(a, b)) {
using std::swap;
swap(a, b);
}
}
std::minmax returns pair of smallest and largest element. Which you can use with std::tie.
#include <algorithm>
#include <tuple>
#include <iostream>
int main()
{
int a = 7;
int b = 5;
std::tie(a, b) = std::minmax({a,b});
std::cout << a << " " << b; // output: 5 7
}
Note that this isn't the same as the if(a < b) std::swap(a,b); version. For example this doesn't work with move-only elements.
if the data type of your value that you're going to compare is not already in c++. You need to overload the comparison operators.
For example, if you want to compare foo1 and foo2
template <class T>
class Foo {
private:
int value; // value
public:
int GetValue() const {
return value;
}
};
bool operator<(const Foo& lhs, const Foo& rhs) {
return (lhs.GetValue() < rhs.GetValue());
}
If your value is some type of int, or double. Then you can use the std::list<>::sort member function.
For example:
std::list<int> integer_list;
int_list.push_back(1);
int_list.push_back(8);
int_list.push_back(9);
int_list.push_back(7);
int_list.sort();
for(std::list<int>::iterator list_iter = int_list.begin(); list_iter != int_list.end(); list_iter++)
{
std::cout<<*list_iter<<endl;
}
I ran into a problem.
I have a class A,and a class that inherits from A,lets call it class B.
I have virtual functions.
I want to compare A and B to another class C by operator==.
If i want to have a list of A's,lets say in stl list,
I must use a pointer to A,so it will look like:
list<*A> list;
and also i have: C something
but now,i cant use the function:find(list.begin(),list.end(),something)
because i cant use operator == for pointers(*).
I found a solution but i dont think its the best,so my question is-can i do it better?
iter=list.begin();
for(iter;iter!=list.end();++iter)
{
if((*iter).operator==(something)
return ...
}
Thank you.
You could use find_if, which lets you provide a function to check for equal values.
auto check_something =
[&something](const list<*A>::iterator& iter){return *iter == something; };
find_if(list.begin(),list.end(),check_something)
You can use
if(**iter == something)
if you want to dereference the pointer.
In C++1x, there is also
for(auto ptr : list)
if(*ptr == something)
Nothing says you can't make a global non-member operator == that operates on pointers or combinations of pointers and objects. If you have many types you could template the combination of pointer vs object equality for any type.
Edit to add this tip: Put the comparison in a namespace with your objects and then argument dependent lookup will find it without putting a global T* == T in scope that catches everything:
namespace equals {
struct A {
A(int x) :x(x) { }
bool operator == (const A &other) const {
return other.x == x;
}
int x;
};
template <typename T>
bool operator == (const T *lhs, const T &rhs) {
return *lhs == rhs;
}
template <typename T>
bool operator == (const T &lhs, const T *rhs) {
return lhs == *rhs;
}
}
Now you can do things like:
equals::A b(1), c(1);
if (b == &c) std::cerr << "good!" << std::endl;
You might have a look at boost::indirect_iterator which is designed for just this purpose.
find(
boost::make_indirect_iterator( list.begin() ),
boost::make_indirect_iterator( list.end() ),
something );
I have a problem with the operator < that i wrote:
in Node.h :
.
..
bool operator<(const Node<T>& other) const;
const T& GetData ();
.
..
template <class T>
const T& Node<T>::GetData () {
return m_data;
}
template <class T>
bool Node<T>:: operator<(const Node<T>& other) const
{
return (*(this->GetData()) < *(other.GetData()));
}
in Heap.h :
template<class T>
void Heap<T>::Insert(Node<T>* newNode) {
if (m_heap.size() == 0) {
m_heap.push_back(newNode);
}
else
DecreaseKey(newNode);
}
template<class T>
void Heap<T>::DecreaseKey(Node<T>* newNode) {
m_heap.push_back(newNode);
int index = m_heap.size();
while ((index > 1) && (m_heap[(index/2)-1] < (m_heap[index-1]))) { // doen't do the operator < !
Exchange(index,index/2);
index = index/2;
}
}
in Vehicle.h:
bool operator< (const Vehicle& otherVehicle) const;
in Vehicle.cpp:
bool Vehicle::operator<(const Vehicle& otherVehicle) const {
return (GetDistance() > otherVehicle.GetDistance());
}
in main.cpp:
.
..
Node<Vehicle*> a(car1);
Node<Vehicle*> b(car2);
Heap<Vehicle*> heap;
Node<Vehicle*>* p = &a;
Node<Vehicle*>* q = &b;
heap.Insert(p);
heap.Insert(q);
heap.ExtractMin()->GetData()->Show();
.
..
Why it doen't do the compeare ? with opeartor < , note: it pass the compiler.
m_heap is a container of pointers. In this case you should dereference the node pointers:
while ((index > 1) && (*m_heap[(index/2)-1] < (*m_heap[index-1])))
This should now call operator< for Nodes, which in turn calls operator< for Vehicles.
Because you used Vehicle*, not Vehicle.
Use std::priority_queue instead of Heap, or any other heap that allows you to define custom comparison predicate.
From what I see m_heap stores pointer to Node
while ((index > 1) && (m_heap[(index/2)-1] < (m_heap[index-1]))) { // doen't do the operator <
I guess this should do
while ((index > 1) && (*(m_heap[(index/2)-1]) < *(m_heap[index-1]))) {
Short answer: don't use pointers. You probably don't need them.
If possible, it's much easier to get this kind of code correct if you use plain objects. If you need to use the concept of a pointer, use a pointer-container class, i.e. a wrapper that is passed around as a plain object with value semantics and potentially custom overloads such as the operator< you're using, but which hides the implementation pointer internally.
That way, you don't need to deal with pointers all over your app, but only where semantically relevant.