Error:
error C2678: binary '==' : no operator found which takes a left-hand operand of type 'const entry' (or there is no acceptable conversion)
The function:
template <class T, int maxSize>
int indexList<T, maxSize>::search(const T& target) const
{
for (int i = 0; i < maxSize; i++)
if (elements[i] == target) //ERROR???
return i; // target found at position i
// target not found
return -1;
}
indexList.h
indexList.cpp
Is this suppose to be an overloaded operator? Being a template class I am not sure I understand the error?
Solution-
The overload function in the class now declared const:
//Operators
bool entry::operator == (const entry& dE) const <--
{
return (name ==dE.name);
}
Start by reading the error text exactly as it is:
binary '==' : no operator found which takes a left-hand operand of type 'const entry'
It means it can't find any == operator that accepts an entry type as its left operand. This code isn't valid:
entry const e;
if (e == foo)
You've showed us the code for your list class, but that's not what the error is about. The error is about a lack of operators for the entry type, whatever that is. Either give the class an operator== function, or declare a standalone operator== function that accepts a const entry& as its first parameter.
struct entry {
bool operator==(const entry& other) const;
};
// or
bool operator==(const entry& lhs, const entry& rhs);
I think the latter is the preferred style.
The problem refers to the type T that is being used in this instance not having an operator== defined. I would guess from your question that this is a class 'entry'.
It might also be that the 'entry' class does not have the operator== defined correctly to take a const entry& as a parameter.
This is likely "const poisoning", where your use of const in the declaration of your search function will force you to add const versions of all the downstream functions you call.
In a function declared const, the this pointer is considered const, which means that all the members you use through that pointer are considered const as well. If your operator == () for whatever type T you are specializing with doesn't explicitly specify const parameters, you will get this error.
If you can't ensure that all Ts you use will have the proper operator == () calls, I'd remove the const specifiers on the member function templates.
The type T you're using as a parameter to this class should have an operator==() since the code you give doesn't contain the instantiation of the template its difficult to know what's wrong.
On a different note, the function definitions of a template should be in the .h file along with the class or else the compiler would not be able to instantiate it properly.
The equality operator for user-defined types is not defined by default. This doesn't have anything to do with your template class, but rather your struct or class "entry".
Therefore in you'll have to override the equality operator in struct entry or class entry.
Alternatively, if you don't want to force everything that uses that template to define an equality operator, you can modify the template interface to accept a Comparator that does the equality comparison.
Sometimes it is quite enough to write
...
if (target == elements[i])
...
Related
I'm new to cC++. I hope the code snippet explains well enough what I'm trying to achieve. I want a global and a element function for overloading of the < operator. In the element function the return type is bool and in the global function it is the respective type. Is this code possible to realize? (Not working right now?)
class Foo{
//...
//element function:
bool operator<(const Foo& otherFoo){//implementation}
}
//global function:
Foo& operator<(const Foo& foo1, const Foo& f2)
{
if (f1.operator<(f2))
return f1;
else;
return f2;
}
Is this code possible to realize?
Yes. But you really, really, really should not do it! operator< has a very concise meaning: Is the left hand side "less" (for some definition of "less") than the right hand side?
Returning the object which is actually "less" is also a reasonable function, but it should be named accordingly! Call it lesser_of or something like that.
Not working right now?
You did not include any useful error description in your question, but I highly suspect that the issue here is const correctness. You're accepting a reference to a const qualified Foo and try to call its member function operator< which is not const qualified. The simple fix: Add a const to the member function:
// member function: vvvvv
bool operator<(const Foo& otherFoo) const {
// implementation ^^^^^
}
The supposed free (= non-member) function (which should really be called with a reasonable name, I chose lesser_of) can be implemented for all types with a corresponding member function, using a template:
template<typename L, typename R>
typename std::common_type<L,R>::type lesser_of(L&& left, R&& right) {
using std::forward;
// Could also use operator<(forward<L>(left), forward<R>(right)), but
// this breaks when there's both a member function and a free
// function available.
if (left.operator<(forward<R>(right))) {
return forward<L>(left);
} else {
return forward<R>(right);
}
}
Note that I have no idea whether the forwarding makes any sense, nor am I sure if this could lead to dangling references.
Going a bit further, there's one kind of usage that I would consider "only just ok" if you really insist on returning "more" than a bool from operator<: In Common Lisp this is called "generalized boolean", and basically means that anything except a special nil value is considered to be "truthy". You could "port" that to C++ and use std::optional (C++17!) to convey that meaning:
template<typename L, typename R>
std::experimental::optional<L> operator<(L&& left, R&& right) {
if (left.operator<(std::forward<R>(right))) {
return std::forward<L>(left);
} else {
return std::experimental::nullopt_t{};
}
}
This returns the left operand wrapped in a std::optional if indeed it is "less" than the right. The result can be checked for in e.g. an if (or similar "special context") because it has a (explicit) conversion member function to bool. Thus returning std::optional instead of bool won't break code that uses the comparison only where contextual conversions can be applied. The returned value can be access by dereferencing or for example the value member function.
Of course this does not allow code like Foo c = a < b;, but you could instead use Foo c = (a < b).value_or(b);.
I want to use my class as key in a map, so I overload operator+. It works well if I overload it as a friend function. When I overload it as a member function inside the class, it causes a compile error.
error C2678: binary '<': no operator found which takes a left-hand operand of type 'const Syl' (or there is no acceptable conversion)'.
In details, this doesn't compile, and generate the compile error:
Syl.h
bool operator< (const Syl& rhs);
Syl.cpp
bool Syl::operator< (const Syl& rhs) { return false; }
While this compiles.
Syl.h
friend bool operator< (const Syl& lhs, const Syl& rhs);
Syl.cpp
bool operator< (const Syl& lhs, const Syl& rhs) { return false; }
I don't know why. I know that operator< is binary, but is there anyway to overload it as function member?
Typically, member operators such as operator< do not modify the object they operate on. If that is the case you need to specify that the method is constant by putting the keyword const at the end of the declaration, i.e.
class Syl {
...
public:
bool operator<(const Syl& rhs) const;
}
An operator like that can be used with STL containers such as std::map.
Your current version of the member operator, when translated into a stand-alone operator would look as:
friend bool operator<(Syl& lhs, const Syl& rhs);
Notice the lack of const for lhs. It is still correct per se, but atypical. You need to provide an l-value as lhs. If you provide something else you get the ``no operator found...'' error. STL std::map does not expect that either, hence your error, probably originating from standard headers, somewhere deep in the template implementation.
Assuming a and b are both of type Syl, your first (member form) is not valid in an expression a < b if a is const, and will result in a compilation error.
To fix that, you need to specify the member operator<() as
bool operator< (const Syl& rhs) const; // note the trailing const
Without that trailing const, in an expression a < b, a cannot be const (i.e. the operator<() is permitted to change it).
Your second form is correct, since it specifies that both operands are const references.
Comparison operators like < don't generally change EITHER of their operands. The const qualifiers communicate that fact.
Bear in mind that you can provide the member form OR the non-member form. Providing both will cause an error due to ambiguity (the compiler has no basis to prefer one over the other, when it sees an expression like a < b).
Is it possible to define different = operators for different template arguments. Let's assume that I want to use different methods for converting arguments of different types:
template <class T,class U>
class cTest
{
private:
public:
T x;
U y;
//typical case
cTest<T,U>& operator =(const cTest<T,U> &that)
{
return *this;
}
//operator = based on the LHS type 1
cTest<uint16_t,U>& operator =(const cTest<int,U> &that)
{
cout<<"cTest<uint16_t,U>& operator =(const cTest<int,U> &that)"<<endl;
return cTest<uint16_t,U>();
}
//operator = based on the LHS type 2
cTest<uint8_t,U>& operator =(const cTest<int,U> &that)
{
cout<<"cTest<uint8_t,U>& operator =(const cTest<int,U> &that)"<<endl;
return cTest<uint16_t,U>();
}
};
You are trying to overload operators/functions by return type. This is not allowed by the C++ standard:
13.1/2: Certain function declarations cannot be overloaded: — Function declarations that differ only in the return type cannot be
overloaded.
Possible workarounds:
You could consider using a function instead on an operator, passing by reference a variable for storing the return value. In this case the overload would be possible. But it's less handy than the assignment operator, and I guess that's no what you were looking for.
A better approach would be to add a separate conversion operator between cTest<uint16_t,U> and cTest<uint8_t,U>.
I suggest that you have a look at Template Metaprogramming.
Template Metaprogramming is a generic programming technique that uses extremely early binding. The compiler acts as an interpreter or a "virtual computer" that emits the instructions that make up the final program. It can be used for static configuration, adaptive programs, optimization and much more.
You can basically let the compiler decide what template definition to use, depending on the respective values. An example for a quaternion multiplication would look like:
template <typename Quaternion>
typename std::enable_if_t<sds::is_quaternion<Quaternion>::value, Quaternion>
operator+(const Quaternion &a, const Quaternion &b)
{
return Quaternion
(
a.u() + b.u(),
a.v() + b.v()
);
}
I have a type called MyType that is an int:
typedef int MyType;
It gets treated as an int throughout the code.
I'd like to be able to overload an operator separately for both int and MyType:
class C
{
public:
C& operator>>(int i) {}
C& operator>>(MyType i) {}
};
but I can't:
overload.cpp:7:7: error: 'C& C::operator>>(MyType)' cannot be overloaded
overload.cpp:6:7: error: with 'C& C::operator>>(int)'
Can I have my cake and eat it too?
As per usual, you need a strong typedef. One implementation of that is BOOST_STRONG_TYPEDEF.
As #Cat++ said, BOOST_STRONG_TYPEDEF is a good solution. However for those who don't want to rely on boost library (no mistake if you do) it is easier to do it this way:
#define TYPEDEF(original_type,target_type)struct target_type{\
original_type value;\
explicit target_type(const original_type val):value(val){}\
target_type(){}\
target_type(const target_type& other):value(other.value){}\
target_type& operator=(const original_type& rhs){value = rhs; return *this;}\
target_type& operator=(const target_type& rhs){value = rhs.value; return *this;}\
bool operator==(const target_type& rhs){return value == rhs.value;}\
bool operator<(const target_type& rhs){return value < rhs.value;}\
operator const original_type&() const{return value;}\
operator original_type&(){return value;}\
}
Usage: TYPEDEF(int, MyType);
So What Does this Macro Do?
This macro basically creates a new structure that can easily be treated as the original type in many ways. And to the compiler this is a totally different type.
Take your MyType for instance. When you declare it as typedef int MyType;, at compile time, MyType gets replaced by int. And since you already have a function defined with int as the parameter, it would complain about duplicate function body.
When you do TYPEDEF(int, MyType);, MyType is a structure that can be initialized and assigned a value of int type and would be treated by the compiler as a totally different data-type from int. Yet you will be able to assign it int values because of the operator = function and retrieve its value as an int because of its operator const original_type&() const and operator original_type&() functions.
This roughly what boost does with its BOOST_STRONG_TYPEDEF macro but it seems to be inheriting from other internal classes and I'm not sure what those classes does. But this is a crude solution for those who don't want to rely on boost for whatever reason.
My Personal Recommendation: Use boost whenever possible.
Why it is not allowed to overload "=" using friend function?
I have written a small program but it is giving error.
class comp
{
int real;
int imaginary;
public:
comp(){real=0; imaginary=0;}
void show(){cout << "Real="<<real<<" Imaginary="<<imaginary<<endl;}
void set(int i,int j){real=i;imaginary=j;}
friend comp operator=(comp &op1,const comp &op2);
};
comp operator=(comp &op1,const comp &op2)
{
op1.imaginary=op2.imaginary;
op1.real=op2.real;
return op1;
}
int main()
{
comp a,b;
a.set(10,20);
b=a;
b.show();
return 0;
}
The compilation gives the following error :-
[root#dogmatix stackoverflow]# g++ prog4.cpp
prog4.cpp:11: error: ‘comp operator=(comp&, const comp&)’ must be a nonstatic member function
prog4.cpp:14: error: ‘comp operator=(comp&, const comp&)’ must be a nonstatic member function
prog4.cpp: In function ‘int main()’:
prog4.cpp:25: error: ambiguous overload for ‘operator=’ in ‘b = a’
prog4.cpp:4: note: candidates are: comp& comp::operator=(const comp&)
prog4.cpp:14: note: comp operator=(comp&, const comp&)
Because if you do not declare it as a class member compiler will make one up for you and it will introduce ambiguity.
The assignment operator is explicitly required to be a class member operator. That is a sufficient reason for the compiler to fail to compile your code. Assignment is one of the special member functions defined in the standard (like the copy constructor) that will be generated by the compiler if you do not provide your own.
Unlike other operations that can be understood as external to the left hand side operator, the assignment is an operation that is semantically bound to the left hand side: modify this instance to be equal to the right hand side instance (by some definition of equal), so it makes sense to have it as an operation of the class and not an external operation. On the other hand, other operators as addition are not bound to a particular instance: is a+b an operation of a or b or none of them? -- a and b are used in the operation, but the operation acts on the result value that is returned.
That approach is actually recommended and used: define operator+= (that applies to the instance) as a member function, and then implement operator+ as a free function that operates on the result:
struct example {
example& operator+=( const example& rhs );
};
example operator+( const example& lhs, const example& rhs ) {
example ret( lhs );
ret += rhs;
return ret;
}
// usually implemented as:
// example operator+( example lhs, const example& rhs ) {
// return lhs += rhs; // note that lhs is actually a copy, not the real lhs
//}
Assignment(=) operator is a special operator that will be provided by the constructor to the class when programmer has not provided(overloaded) as member of the class.(like copy constructor).
When programmer is overloading = operator using friend function, two = operations will exists:
1) compiler is providing = operator
2) programmer is providing(overloading) = operator by friend function.
Then simply ambiguity will be created and compiler will gives error. Its compilation error.
There is no good reason for that, I think Stepanov proposed that there should be a free operator= and many good stuff can be done with that (even more than what can be done with the move assignment). I can't find the citation but Stepanov went as a far as to suggest that the constructors could be free functions http://www.stlport.org/resources/StepanovUSA.html.
There is a way around it, which is to systematically declare a template<class Other> A& operator=(Other const& t); in inside all your classes, in this way you leave the option to anyone to define a custom assignment operator.
Of course you can't do this with a class you don't have control over.
Having said that it is nowadays not that bad since we have move assignment. And in some sense conversion operators B::operator A() const{...} are almost like a custom copy assignment. Conversion operators are now usable because of explicit. However you have to have control over the second type (B), the right-hand type in assignment.
Next question is why conversion operator need to be members them selves? Again, I don't think there is a good reason.