Is there a way to by using some metaprogramming trick make situation like this works:
int* get();//this fnc returns pointer to int OR nullptr
int k = 1;
//this is the operator which is supposed to compare value and pointer
template<class T>
bool operator!=(const T& left, const T* right)
{
if (right)
{
return left != *right;
}
else
{
return false;
}
}
//And this is the code fragment which interests me most
if (k != get())
{
///
}
The crux is that I would like NOT TO change this line k != get() and yet for some reason my operator!= seems not to work. What's the problem?
You can only overload operators with at least one user-defined type as an argument. Neither int nor int* are user-defined types.
You can't overload operators for builtin types.
As already mentioned in other answers that you cannot have operator != for non userdefined types like int, char and so on.
One option is to wrap int inside your user defined struct and achieve the goal.
struct Int
{
int i;
// define all the necessary operators/constructor who deal with 'int'
Int(int x) : i(x) {}
bool operator != (const int* right)
{
return (right)? (i != *right) : false;
}
};
Now declare
Int k = 1;
Related
I am trying to use std::equal_range with the structure below I have compilation error saying that error: no match for ‘operator<’ .
struct MyFoo {
int v_;
string n_;
bool operator<(int v) const
{ return v_ < v;}
};
vector<MyFoo> data;
// data is sorted by int v_
typedef vector<MyFoo>::iterator Ptr;
std::pair< Ptr, Ptr > pr = std::equal_range(data.begin(), data.end(), 10);
I've looked into the template implementatino and what is failing is the following where *it is deferenging the iterator pointing to an object of MyFoo and val_ is 10.
if(*it < val_) {
...
}
Why it is not working? I thought probably because it is trying to call the the global operator< that is not defined, but since I defined it as class member that should not be a problem, isn't it?
Provide non-member comparison operators :
bool operator<(int v, const MyFoo& foo)
{
return foo.v_ < v;
}
bool operator<(const MyFoo& foo, int v)
{
return v < foo;
}
Alternatively, you can provide a conversion operator to int :
operator int() cont {return v_;}
Which is probably unwanted, since the compiler will be able to perform silent conversions in other places of your code.
As an other alternative: provide
bool operator<(const MyFoo& rhs) const { return v_ < rhs.v_; }
And use std::equal_range on a dummy object with correct v_ as:
std::pair<Ptr, Ptr> pr = std::equal_range(data.begin(), data.end(), MyFoo{10, ""});
You may be having trouble because the std::equal_range implementation uses std::less. This is going to try to convert your MyFoo to an int to do the comparison, rather than just using an operator<() overload. Try adding this to your MyFoo class...
operator int() const
{
return v_;
}
I was going through code... I found a template class which is declared as shown below.
template <class T>
class tType
{
public:
T value;
T operator=(T val){ value = val; return value; }
tType<T> operator=(tType<T> &val){ value = val.value; return *this; }
operator T(){ return value; }
};
I also found operator overloaded like below...
******1******
template <class T>
bool operator==(T& val, tType<T>& tval) { return(val == tval.value); }
I didn't understand when the above operator gets called... cos when I did...
int main(void)
{
tType<int> x;
x = 5;
if (5 == x)
{
cout << "Both are equal" << endl;
}
return 0;
}
The above said operator was not getting called... and was still working... I also wrote below code for testing and the below code snippet is getting called...
template<class T>
bool operator==(int x, tType<T>& val) { return (x == val.value); }
I wasn't to know who to call *****1*****
It's right that the reason your operator== isn't called is because of the missing const identifier. In this case, the literal 5 is unable to be passed as a variable reference for the paramater T& val. But, that's not quite the whole story.
As you point out, the code still compiles and runs even though the function isn't being called.
The reason your code still works is because of the conversion operator: operator T(){ return value; }.
A conversion operator allows implicit casts from one type to another. For example:
struct Number {
Number(int x) : value(x) { }
operator int() { return value; }
private:
int value;
};
int main() {
Number n(5);
int x = n; // 5 -- operator int() at work
int y = n + x; // 10 -- operator int() at work
Number z = x + y; // 15 -- Number(int) at work
cout << x <<" "<< y <<" "<< z << endl;
return 0;
}
Here, operator int() allows n to convert into an int for assignment to x and to convert to an int for addition with x (the resultant int is then assigned to y), while the unary constructor Number(int) allows the result of x + y to convert back to a Number.
In your code, 5 == x still compiles because the tType<int> x is converted into an int via its operator int() member function, and then that resultant int is compared against the literal 5.
However, this probably isn't a very good design for a class. For example, in order to compare two tType<T>s, a cast into T will be required for one of them.
template <class T>
bool operator==(const T& val, const tType<T>& tval) {
cout << "operator==(const T& val, const tType<T>& tval) was called." << endl;
return(val == tval.value);
}
//...
cout << ( tType<int>() == tType<int>() ) << endl; // calls operator==(const T&, const tType<T>&)
You would rather have an operator== for two tType<T>s.
Another even bigger problem is that this is not symmetric:
cout << (x1 == 5) << endl; // calls operator==(int,int) (the built-in function)
Yikes!
To address all of these, there is a very straightforward design solution. This is taken from Scott Meyers' book Effective C++ Third Edition (a phenomenal book).
Instead of converting back to a T with a conversion operator, the class should include an implicit unary constructor to convert T's up to tType<T>s, and should declare exactly one operator== for tType<T>s:
template <class T>
class tType
{
public:
tType<T>(const T &val) : value(val) { } // unary non-explicit constructor
tType<T> operator=(const tType<T> &val){ value = val.value; return *this; } // only need one
T val() { return value; }
private:
T value; // Note also value is private (encapsulation)
};
template<class T>
bool operator==(const tType<T>& a, const tType<T>& b) { return ( a.val() == b.val() ); }
The important changes:
Added a constructor that takes a single value; this allows converting Ts into tTypes.
Removed the assignment operator taking Ts (because now we can convert them to tTypes.
Only have one equality operator and it takes two const tType<T>&s, meaning operator== can handle any combination of Ts and tType<T>s (or, even better, anything convertible into either of those).
The == operator attempts to bind non-const references to the arguments - values like "5" are not amenable to that... the parameters should be const:
template <class T>
bool operator==(const T& val, const tType<T>& tval) { return val == tval.value; }
As that will still only support e.g. 5 == my_tType and not my_tType == 5, you may want to also provide...
template <class T>
bool operator==(const tType<T>& tval, const T& val) { return val == tval.value; }
...and for my_tType1 == my_tType2...
template <class T>
bool operator==(const tType<T>& tval1, const tType<T>& tval2) {
return tval1.value == tval2.value; }
This gives you maximum control of the comparisons. An alternative is to allow implicit construction of a tType from a T argument, but implicit construction and conversion operators are generally discouraged these days - they can lead to ambiguities and accidental creation of temporaries that can be hard to debug. A topic for another question....
When you say "The above said operator was not getting called... and was still working" - what was actually happening was that tType::operator T() (which returns value;) was being implicitly called, returning an int that could be compared - as an int - to 5. Hence - you had a comparison, but not using the custom operator==. This is a normal result of finding the "best match" for a function call.
Change the function
template <class T>
bool operator==(T& val, tType<T>& tval) { return(val == tval.value); }
to
template <class T>
bool operator==(T const& val, tType<T> const& tval) { return(val == tval.value); }
or
template <class T>
bool operator==(T val, tType<T> tval) { return(val == tval.value); }
Your function was not getting called since 5 cannot be converted to int&.
I am learning templates and operator overloading. I have written some code but I am confused... Let me explain...
template <class T>
class tempType
{
public:
T value;
bool locked;
tempType():locked(false)
{
value = 0;
}
T operator=(T val)
{
value=val;
return value;
}
tempType<T> operator=(tempType<T> &val)
{
value=val.value;
return *this;
}
operator T()
{
return value;
}
};
And I did...
int main(void)
{
tempType<int> i;
tempType<bool> b;
tempType<float> f;
i.value = 10;
i = i + f;
return 0;
}
What code I need to write in order to execute
tempType<T> operator=(tempType<T> &val){}
Also, I why operator T() is required?
Unless you implement move semantics, operator= should always take a const & reference to the source value. It should also return a reference to the modified object.
tempType & operator=(T const & val)
{
value=val;
return * this;
}
operator T is an implicit conversion function which allows any tempType object to be treated as an object of its underlying type T. Be careful when specifying implicit conversions that they won't conflict with each other.
An implicit conversion function usually shouldn't make a copy, so you probably want
operator T & ()
{
return value;
}
operator T const & () const
{
return value;
}
Given these, you shouldn't need another overload of operator = because the first overload will simply be adapted by the conversion function to a call such as i = b;.
If a series of conversions will result in the operator=(T const & val) being called, you should avoid also defining operator=(tempType const & val) because the overloads will compete on the basis of which conversion sequence is "better," which can result in a brittle (finicky) interface that may refuse to do seemingly reasonable things.
I think I know all the answers so I might as well post full response.
To override default operator= you should declare it as tempType<T> operator=(const tempType<T> &val){}. Now you need to call the method explicitly via i.operator=(other_i).
If you correct the declaration you can use it like this:
tempType<int> i;
tempType<int> other_i;
i = other_i; // this is what you just defined
The operator T() is called a conversion operator. It is kind of reverse or counter part of the conversion constructor which in your case would be tempType(const &T value).
It is used to convert a class object into a given type. So in your case you would be able to write:
tempType<int> i;
int some_int;
some_int = i; // tempType<int> gets converted into int via `operator int()`
template <class T>
class tempType
{
public:
T value;
bool locked;
tempType() : value(), locked(false)
{
value = 0;
}
//althought legal, returning something different from tempType&
//from an operator= is bad practice
T operator=(T val)
{
value=val;
return value;
}
tempType& operator=(const tempType &val)
{
value=val.value;
return *this;
}
operator T()
{
return value;
}
};
int main(void)
{
tempType<int> a;
tempType<int> b;
a = b;
return 0;
}
in the code, a = b calls the operator.
As for the second question, the operator T() is not needed "by default". In your example, it is used when you write i+f:
i is converted to an int
f is converted to a float
the operation (+) is performed
T tempType<int>::operator=(T val) is called for the assignement
I have such code
class Number
{
int m_value;
public :
Number(const int value) :
m_value(value)
{
}
operator const int() const
{
return m_value;
}
int GetValue() const
{
return m_value;
}
};
bool operator==(const Number& left, const Number& right)
{
return left.GetValue() == right.GetValue();
}
class Integer
{
int m_value;
public :
Integer(const int value) :
m_value(value)
{
}
operator const int() const
{
return m_value;
}
bool operator==(const Integer& right) const
{
return m_value == right.m_value;
}
bool operator==(const int right) const
{
return m_value == right;
}
int GetValue() const
{
return m_value;
}
};
bool operator==(const int left, const Integer& right)
{
return left == right.GetValue();
}
int main()
{
Number n1 = 1;
Number n2 = 1;
int x3 = 1;
n1 == n2;
n1 == x3; // error C2666: 'operator ==' : 3 overloads have similar conversions
x3 == n1; // error C2666: 'operator ==' : 2 overloads have similar conversions
Integer i4 = 1;
Integer i5 = 1;
i4 == i5;
i4 == x3;
x3 == i4;
return 0;
}
For class Number I have two errors as shown in the code above. For class Integer everything is OK. The problem is, I want to keep in resulting class single-parameter constructor, cast operator and equality operations (MyClass == int, int == MyClass, MyClass == MyClass), but I want to implement only one version of operator== as in class Number. I don't see any way to do this. Is that even possible or I must have all three implementations as in class Integer? I know why I get these errors I just don't like the solution I have.
In class Number you define a conversion operator to int and your constructor allows converting an int to a Number. Therefore, when comparing a Number n and an int x for equality, ambiguity arises: should the compiler invoke the built-in operator == for ints and convert n to an int, or should it rather pick your operator and convert x to a Number? Both conversions are equally good, and it can't choose one.
So yes you have to define three versions, or add a template operator which can perfectly match the type of all arguments and forward to your operator explicitly, like this one (but you most likely want to guard it with some enable_if to limit its applicability only to the appropriate T and U):
template<typename T, typename U> // beware: this will match anything. to be constrained
bool operator == (T n, U const& u)
{
return (Number(n) == Number(u));
}
You can define only one operator== as member function:
bool operator==(const int& right) const
{
std::cout << "custom\n";
return this->GetValue() == right;
}
Then,
n1==n2: n2 will be converted to int and custom operator will be used.
n1 == n3: custom operator will be used
n3==n1: built-in operator will be used
Note, that you want your operator== be const to be able to compare constant Numbers
In C++11 you can make operator int explicit.
Another approach would be to use SFINAE to have a template == that works for one or more Number args, but that is using a bazooka to kill an ant.
I am trying sort std::vector using algorithm::sort , But I am getting runtime error
Invalid operator <.
Following is my code.
struct Point {
double x_cord;
double y_cord;
int id;
Point(int d, double x, double y) {
x_cord = x;
y_cord = y;
id = d;
}
};
struct compareX {
bool operator ()(Point * left, Point* right) const {
if (left->x_cord < right->x_cord)
return true;
return true;
}
};
struct compareY {
bool operator ()(Point * left, Point* right) const {
if (left->y_cord <= right->y_cord) return true;
return true;
}
};
Here is now I am calling it after populating the values.
std::sort( posVector.begin(), posVector.end(), compareX());
Your comparison function always returns true!
Your comparison functions always seem to return true. Returning false occasionally might be a good idea. And (to be serious) comparing (x.y) coordinates is not as trivial as it might seem to be - you probably want to think about it a bit before implementing it.
If you are using std::vector<Point> then must be
struct compareX {
bool operator ()(const Point& left, const Point& right) const {
return left.x_cord < right.x_cord;
}
};
struct compareY {
bool operator ()(const Point& left, const Point& right) const {
return left->y_cord < right->y_cord;
}
};
The problems of your code are
comparison classes accept pointers instead of objects being sorted (if std::vector<Point> is sorted, i.e. not std::vector<Point*>). If you are sorting vector of pointers then it is fine.
comparison classes contain mistyping - always return true (as already mentioned)
compareY use <= instead of <. It is bad idea because standard algorithms (including sorting) expect less-semantic (not less_or_equal-semantic).
Overload the '<' operator for the Point class.