Is it possible to make a custom operator so you can do things like this?
if ("Hello, world!" contains "Hello") ...
Note: this is a separate question from "Is it a good idea to..." ;)
Yes! (well, sort of)
There are a couple publicly available tools to help you out. Both use preprocessor code generation to create templates which implement the custom operators. These operators consist of one or more built-in operators in conjunction with an identifier.
Since these aren't actually custom operators, but merely tricks of operator overloading, there are a few caveats:
Macros are evil. If you make a mistake, the compiler will be all but entirely useless for tracking down the problem.
Even if you get the macro right, if there is an error in your usage of the operator or in the definition of your operation, the compiler will be only slightly more helpful.
You must use a valid identifier as part of the operator. If you want a more symbol-like operator, you can use _, o or similarly simple alphanumerics.
CustomOperators
While I was working on my own library for this purpose (see below) I came across this project. Here is an example of creating an avg operator:
#define avg BinaryOperatorDefinition(_op_avg, /)
DeclareBinaryOperator(_op_avg)
DeclareOperatorLeftType(_op_avg, /, double);
inline double _op_avg(double l, double r)
{
return (l + r) / 2;
}
BindBinaryOperator(double, _op_avg, /, double, double)
IdOp
What started as an exercise in pure frivolity became my own take on this problem. Here's a similar example:
template<typename T> class AvgOp {
public:
T operator()(const T& left, const T& right)
{
return (left + right) / 2;
}
};
IDOP_CREATE_LEFT_HANDED(<, _avg_, >, AvgOp)
#define avg <_avg_>
Key Differences
CustomOperators supports postfix unary operators
IdOp templates use references rather than pointers to eliminate use of the free store, and to allow full compile-time evaluation of the operation
IdOp allows you to easily specify several operations for the same root identifier
There's a method thoroughly explored in 'Syntactic Aspartame' by Sander Stoks that would allow you to use the following format:
if ("Hello, world!" <contains> "Hello") ...
In essence, you need a proxy object with the operators '<' and '>' overloaded. The proxy does all of the work; 'contains' can just be a singleton with no behavior or data of its own.
// Not my code!
const struct contains_ {} contains;
template <typename T>
struct ContainsProxy
{
ContainsProxy(const T& t): t_(t) {}
const T& t_;
};
template <typename T>
ContainsProxy<T> operator<(const T& lhs, const contains_& rhs)
{
return ContainsProxy<T>(lhs);
}
bool operator>(const ContainsProxy<Rect>& lhs, const Rect& rhs)
{
return lhs.t_.left <= rhs.left &&
lhs.t_.top <= rhs.top &&
lhs.t_.right >= rhs.right &&
lhs.t_.bottom >= rhs.bottom;
}
I've created the following two macros:
#define define const struct
#define operator(ReturnType, OperatorName, FirstOperandType, SecondOperandType) OperatorName ## _ {} OperatorName; template <typename T> struct OperatorName ## Proxy{public:OperatorName ## Proxy(const T& t) : t_(t){}const T& t_;static ReturnType _ ## OperatorName ## _(const FirstOperandType a, const SecondOperandType b);};template <typename T> OperatorName ## Proxy<T> operator<(const T& lhs, const OperatorName ## _& rhs){return OperatorName ## Proxy<T>(lhs);}ReturnType operator>(const OperatorName ## Proxy<FirstOperandType>& lhs, const SecondOperandType& rhs){return OperatorName ## Proxy<FirstOperandType>::_ ## OperatorName ## _(lhs.t_, rhs);}template <typename T> inline ReturnType OperatorName ## Proxy<T>::_ ## OperatorName ## _(const FirstOperandType a, const SecondOperandType b)
Then, you'd have just to define your custom operator as in the following example:
define operator(bool, myOr, bool, bool) { // Arguments are the return type, the name of the operator, the left operand type and the right operand type, respectively
return a || b;
}
#define myOr <myOr> // Finally, you have to define a macro to avoid to put the < and > operator at the start and end of the operator name
Once a time you've set your operator up, you can use it as a predefined operator:
bool a = true myOr false;
// a == true
Warning
While this has been an interesting exercise, it merely demonstrates how bad is to have a macro–enabled precompiler. Adding custom operators like this can easily lead to a sort of metalanguage. Although we know how badly is C++ designed (most of all considering that it was first conceived as a set of extensions for C), we shouldn't be changing it. If you can't use standard C++, which is the only way to keep the code understandable by other people, you should just switch to another language that makes what you wish to do the way you'd like. There are thousands languages — no need to mess around with C++ to make it different.
SHORTLY: You just shouldn't be using this code. You should refrain from using macros unless when only used the same way as inline methods.
To be a bit more accurate, C++ itself only supports creating new overloads of existing operations, NOT creating new operators. There are languages (e.g., ML and most of its descendants) that do allow you to create entirely new operators, but C++ is not one of them.
From the looks of things, (at least) the CustomOperators library mentioned in the other answer doesn't support entirely custom operators either. At least if I'm reading things correctly, it's (internally) translating your custom operator into an overload of an existing operator. That makes things easier, at the expense of some flexibility -- for example, when you create a new operator in ML, you can give it precedence different from that of any built-in operator.
Technically, no. That is to say, you can't extend the set of operator+, operator-, etcetera. But what you're proposing in your example is something else. You are wondering if there is a definition of "contains" such that string-literal "contains" string-literal is an expression, with non-trivial logic (#define contains "" being the trivial case).
There are not many expressions that can have the form string-literal X string-literal. This is because string literals themselves are expressions. So, you're looking for a language rule of the form expr X expr. There are quite a few of those, but they're all rules for operators, and those don't work on strings. Despite the obvious implementation, "Hello, " + "world" is not a valid expression. So, what else can X be in string-literal X string-literal ? It can't be a expression itself. It can't be a typename, a typedef name or a template name. It can't be a function name. It can really only be a macro, which are the only remaining named entities. For that, see the "Yes (well, sort of)" answer.
As others have pointed out you sadly can not write custom operators but with macros you can get similar behaviour. It is actually really easy with c style casting see below.
class To_Range{
public:
size_t start;
size_t end;
To_Range(size_t _start,size_t _end) :
start(_start), end(_end) {}
};
class Slicing_To_End{
public:
int end;
Slicing_To_End(const int& init) : end(init) {}
};
To_Range operator == (const int& start,const Slicing_To_End& end) {
return To_Range(start,end.end);
}
#define to == (Slicing_To_End)
Here 4 to 5 will give back an object of type To_Range. (Slicing_To_End) casts 5 to Slicing_To_End. Now the compiler wants to find an == operator that fits. The only one is our custom operator that takes as input an integer on the first position and in the second Slicing_To_End and returns our type To_Range. You also could return of course other types like int,float.
Your suggestion would be nothing more than syntactic sugar for:
if( contains( "Hello, world!", "Hello" ) ...
and in fact there are already a functions to do that in both cstring and std::string. Which is perhaps a bit like answering "is it a good idea?" but not quite; rather asking "why would you need/want to?"
Related
It is easy to introduce new infix operators in C++
// User-defined infix operator framework
template <typename LeftOperand, typename Operation>
struct LeftHelper
{
const LeftOperand& leftOperand;
const Operation& operation;
LeftHelper(const LeftOperand& leftOperand,
const Operation& operation)
: leftOperand(leftOperand), operation(operation) {}
};
template <typename LeftOperand, typename Operation >
auto operator < (const LeftOperand& leftOperand,
Operation& operation)
{
return LeftHelper<LeftOperand, Operation>(leftOperand, operation);
}
template <typename LeftOperand, typename Operation, typename RightOperand>
auto operator > (LeftHelper<LeftOperand, Operation> leftHelper,
const RightOperand& rightOperand)
{
return leftHelper.operation(leftHelper.leftOperand, rightOperand);
}
// Defining a new operator
#include <cmath>
static auto pwr = [](const auto& operand1, const auto& operand2) { return std::pow(operand1, operand2); };
// using it
#include <iostream>
int main()
{
std::cout << (2 <pwr> 16) << std::endl;
return 0;
}
Live demo
Unfortunately, this power operator has wrong precedence and associativity. So my question is: how to fix this? I want my <pow> to have higher precedence than * and associate to the right, just like in the mathematical notation.
Edit It is possible to vary the precedence by using different brackets, e.g. |op|, /op/, *op* or even, if one is so inclined, <<--op-->>, but one cannot go higher than the highest built-in operator precedence this way. But today C++ is so powerful with template metaprogramming and type deduction, there simply ought to be some other way to achieve the desired result.
Additionally, it would be nice if I could use pow and not pwr. Unfortunately in some implementations #include <cmath> brings pow into the global namespace, so there will be a conflict. Can we overload operator not such that a declaration of the form
not using std::pow;
removed std::pow from the global namespace?
Further reading: a related proposal by Bjarne Stroustrup.
The principle of least surprise is important, and it is key that a*b *power* c * d evaluate to a* (b^c) *d. Luckily there is an easy solution.
To ensure that *power* has a higher precedence than multiplication, you have to use a similar named operator technique for multiplication.
Then instead of directly calculating the results of *power* and *times*, you instead build an expression tree. This expression tree, when evaluated, can apply arbitrary precedence rules.
We can do this with every built-in operator, giving us an easy to read syntax that permits compile-time metaprogramming of operator precedence:
auto z =equals= bracket<
a *plus* b *times* c *power* bracket<
a *plus* b
>bracket *power* x *times* y
>bracket;
To avoid this expression template from being stored longer than optimal, simply overload operator auto()&& to return the deduced type. If your compiler fails to support that feature, =equals= can return the proper type at a mild cost of clarity.
Note that the above syntax is actually realizable in C++ using techniques similar to the OP's. An actual implementation is larger than a SO post should contain.
There are other benefits. As everyone knows, obscure ASCII characters in programming languages have fallen out of favor, and people reading C++ may be confuesed by expressions like:
int z = (a + b* pow(c,pow(x,a+b))*y);
With this technique, all operators have readable names that make their meaning clear, and everything is done infix instead of mixing infix and prefix notation.
Similar solutions to ensure that pow is available can be done by reimplementing <cmath> as <cmath_nopow> yourself. This avoids overloading operator not on language constructs, which causes AST grammar monads to decouple, and/or violates the standard. Maybe try Haskell?
MATLAB arrays support matrix operations and element operations. For example, M*N and M.*N. This is a quite intuitive way to distinguish the two different operations. If I want to implement similar operations in C++, how can I do that?
Can I create a new operator, .*, too? If yes, can anyone give me some guidance?
No, you can't overload op.*:
[C++03 & C++11: 13.5/3]: The following operators cannot be overloaded:
. .* :: ?:
In C++, there's a list of predefined operators, most of which are overloadable (.* is not). Additionally, any name can be used as an operator like:
#include <iostream>
// generic LHSlt holder
template<typename LHS, typename OP>
struct LHSlt {
LHS lhs_;
};
// declare myop as an operator-like construct
enum { myop };
// parse 'lhs <myop' into LHSlt
template<typename LHS>
LHSlt<LHS, decltype(myop)> operator<(const LHS& lhs, decltype(myop))
{
return { lhs };
}
// declare (int <myop> int) -> int
int operator>(LHSlt<int, decltype(myop)> lhsof, int rhs)
{
int& lhs = lhsof.lhs_;
// here comes your actual implementation
return (lhs + rhs) * (lhs - rhs);
}
// strictly optional
#define MYOP <myop>
int main() {
std::cout << (5 <myop> 2) << ' ' << (5 MYOP 2);
}
Disclaimer: This, strictly speaking, gets translated to (5 < myop) > 2, which is LHSlt<int, decltype(myop)>(5) > 2. Thus it's not a new 'operator', in C++-terms, but it's used exactly the same way, even in terms of ADL. Also, if type is large, you probably want to store const T&.
Note that you can do this with any binary operator that can be defined external to the class; precedence is based on the precedence of the two sides (< and >). Thus you can have e.g. *myop*, +myop+, <<myop>>, <myop>, |myop| in this order of precedence.
If you want right-associativity, it gets a bit more tricky. You'll need both of a RHS-holder and LHS-holder (the latter being LHSlt here) and use surrounding operators such that the right one has higher precedence than the left one, e.g. a |myop> b |myop>c is a |myop> (b |myop> c). Then you need the function for both your type and your holder type as the lhs.
You cannot overload .* (see Lightness' answer for standard text), but, interestingly enough, you can overload ->* (similar to how you can overload -> but not .). If that's sufficient for differentiation, then have at it:
struct Int {
int i;
Int operator*(Int rhs) const { return Int{i * rhs.i}; }
Int operator->*(Int rhs) const { return Int{i + rhs.i}; }
friend std::ostream& operator<<(std::ostream& os, Int rhs) {
return os << "Int(" << rhs.i << ')';
}
};
int main() {
Int five{5};
Int six{6};
std::cout << (five * six) << ", " << (five ->* six) << '\n';
}
That'll print Int(30), Int(11).
No, unfortunately you cannot define new operators—you can only overload existing operators (with a few important exceptions, such as operator.). Even then, it's typically only a good idea to overload operators for types which have very clear and uncontroversial existing semantics for a given operator—for instance, any type that behaves as a number is a good candidate for overloading the arithmetic and comparison operators, but you should make sure that operator+ doesn't, say, subtract two numbers.
MATLAB arrays support matrix operations and element operations. For example, M*N and M.*N. This is a quite intuitive way to distinguish the two different operations. If I want to implement similar operations in C++, how can I do that?
Can I create a new operator, .*, too? If yes, can anyone give me some guidance?
As for the first part you can overload most of the operators and there are some that you can not overload and the list of operators in C++ are:
Arithmetic
+ (addition)
- (subtraction)
* (multiplication)
/ (division)
% (modulus)
Bitwise
^ (XOR)
| (OR)
& (AND)
~ (Complement)
<< (Shift Left, Insertion to Stream)
>> (Shift Right, Extraction from Stream)
Assignment
= (Assignment)
Relational
== (Equality)
!= (Inequality)
> (Greater-Than)
< (Less-Than)
>= (Greater-Than Or Equal-To)
<= (Less-Than Or Equal-To)
Logical
! (NOT)
&& (AND)
|| (OR)
Compound Assignment
+= (Addition-Assignment)
-= (Subtraction-Assignment)
*= (Multiplication-Assignment)
/= (Division-Assignment)
%= (Modulus-Assignment)
&= (AND-Assignment)
|= (OR-Assignment)
^= (XOR-Assignment)
<<= (Shift-Left Assignment)
>>= (Shift-Right Assignment)
Increment - Decrement - Both have 2 forms (prefix) and (postfix)
++ (Increment)
-- (Decrement)
Subscript
[] (Subscript)
Function Call
() (Function Call)
Address, Reference, Pointer
operator&()
operator*()
operator->()
Comma
operator,()
Member Reference
operator->()
operator->*()
Memory Management
new
delete
new[]
delete[]
Conversion
operator "type" () const
NON Modifiable Operators - Operators that can not be overloaded
?: (Conditional - Ternary)
. (Member Selection)
.* (Member Selection With Pointer To Member)
:: (Scope Resolution)
sizeof() (Object Size Information)
typeid() (Object Type Information)
So knowing this list will help to answer your questions. Can you Create a "New Operator" in C++? No! If you want to implement similar operations in C++; how can I do that?
You have 4 choices: Either overload an already existing operator that can be overloaded, write a function or method to do the type of calculations you want to perform, create a template type to do the work for you, or the last one which is the least common to do but you can also write macros to do them for you.
There is a header only Math API Library that is used quite frequently with OpenGL graphics API and OpenGL's Shader Language GLSL and this library has many features that work with vectors, matrices, quaternions etc., and all the necessary functions and operations that can be done to them. Here is the link to GLM You can have a look at their documentation as well as their library implementations since it is a headers only library or API. This should give you some insight on how they constructed their Vector and Matrix objects and the operations that can be done to them.
BTW: I am seeking to answer the parts of this question as asked. I am also not seeking to replicate all the information in other worthy answers. The bounty seeks something different to the question as asked, so I am not responding to that.
It is actually fairly simple to provide a matrix multiplication. Since I'm not proposing to describe data structures to represent a matrix and fully implement operations and validity checks on them, I'll just provide skeletons to illustrate.
Example 1: operator*() as a member function
class M // a basic matrix class
{
public:
// assume other constructors and members to set things up
M operator*(const M &rhs) const;
};
M M::operator*(const M &rhs) const
{
// implement checks on dimensions, throw an exception if invalid
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
int main()
{
M a;
M b;
// set up elements of a and b as needed
M c = a*b; // this relies on M having appropriate constructor(s) to copy or move the result of a*b into c
M d;
d = a * b; // this relies on M having appropriate operator=() to assign d to the result of a*b
}
The above implements operator*() as a member function. So, functionally, c = a*b is equivalent to c = a.operator*(b). The const qualifiers represent the fact that a matrix multiplication a*b does not generally change a or b.
Example 2: operator*() as a non-member function
Now, operator*() can also be implemented as a non-member (optionally a friend), with a skeleton that looks like
class M // our basic matrix class, different operator *
{
public:
// assume other constructors and members to set things up
friend M operator*(const M &lhs, const M &rhs);
};
M operator*(const M &lhs, const M &rhs)
{
// implement checks on dimensions, throw an exception if invalid
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
// same main() as before
Note that, in this case, a*b is now equivalent to operator*(a, b).
If you want to use both forms, care is needed to avoid ambiguity. If both forms of operator*() are provided they are both valid matches in a statement like c = a*b and the compiler has no means to choose one form over the other. The result is code not compiling.
Example 3: overloading operator*()
It is also possible to overload operator*() - for example, to multiply a matrix by a scalar.
class M // a basic matrix class
{
public:
// assume other constructors and members to set things up
M operator*(const M &rhs) const; // as in first example
M operator*(double scalar) const; // member form
friend M operator*(double scalar, const M &rhs); // non-member form
};
M M::operator*(double scalar) const
{
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
M operator*(double scalar, const M &m)
{
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
int main()
{
M a;
M b;
// set up elements of a and b as needed
M c = b * 2.0; // uses the member form of operator*() above
M d;
d = 2.0*a; // uses the non-member form of operator*() above
}
In the above b*2.0 amounts to a call of b.operator*(2.0) and 2.0*a to a call of the non-member operator*(2.0, a). The member forms can only generally be used in expressions where the left hand operand is of type M. So 2.0*a will not work if only member forms of operator*() is provided.
Discussion
Apart from concerns of ambiguity above, there are other things to be aware of when overloading operators.
It is not possible to change precedence or associativity of operators from their specification in language rules. So, in the expression a+b*c, the * will always have higher precedence than the +. This is also the reason it is not a good idea to overload ^ for exponentiation in C++, since ^ has a lower precedence than + in C++ (being a bitwise operation on integral types). So a + b^c is actually equivalent in C++ to (a + b)^c, not to a + (b^c) (which anyone with basic knowledge of algebra would expect).
The language specifies a set of operators, and it is not possible to create new ones. For example, there is no ** in C++, such that a ** b raises a to the power of b (which other languages can do), and it is not possible to create one.
Not all operators can be overloaded.
One of the operators that cannot be overloaded in C++ is .*. So it is not possible to use such an operator like you would in Matlab. I would generally suggest NOT trying to get the same effect using other operators, because the above constraints will affect that (and cause expressions to give counter-intuitive behaviour). Instead simply provide another named function to do the job. For example, as a member function
class M
{
public:
// other stuff
M ElementWiseProduct(const M &) const;
};
Most of the answers have already covered which operators are and are not overloadable, but none have discussed WHY some are mutable and some aren't.
The following is a quote from Bjarne Stroustrup (the guy who wrote c++) that I found in this stackoverflow answer. Pay particular attention to the third paragraph.
When I decided to allow overloading of operator ->, I naturally considered whether operator . could be similarly overloaded.
At the time, I considered the following arguments conclusive: If obj is a class object then obj.m has a meaning for every member m of that object's class. We try not to make the language mutable by redefining built-in operations (though that rule is violated for = out of dire need, and for unary &).
If we allowed overloading of . for a class X, we would be unable to access members of X by normal means; we would have to use a pointer and ->, but -> and & might also have been re-defined. I wanted an extensible language, not a mutable one.
These arguments are weighty, but not conclusive. In particular, in 1990 Jim Adcock proposed to allow overloading of operator . exactly the way operator -> is.
A page on his website adds a little more:
Can I define my own operators?
Sorry, no. The possibility has been considered several times, but each time I/we decided that the likely problems outweighed the likely benefits.
It's not a language-technical problem. Even when I first considerd it in 1983, I knew how it could be implemented. However, my experience has been that when we go beyond the most trivial examples people seem to have subtlely different opinions of "the obvious" meaning of uses of an operator. A classical example is a ** b ** c. Assume that ** has been made to mean exponentiation. Now should a ** b ** c mean (a ** b) ** c or a ** (b ** c)? I thought the answer was obvious and my friends agreed - and then we found that we didn't agree on which resolution was the obvious one. My conjecture is that such problems would lead to subtle bugs.
So, while most operators can be overloaded, it was never intended for people to create arbitrary operators in c++.
It's as simple (and as difficult!) as defining a function named (in this case) operator*():
Matrix operator*(const Matrix &m1, const Matrix &m2) ...
where Matrix is a class you've defined to represent matrices.
As other answers say, overloading operator.* is not possible.
But I got a good solution for your question, check here.
You can provide any methods in operator-ish form like:
M <matrix_mul> N
Comparing two instances of the following struct, I receive an error:
struct MyStruct1 {
MyStruct1(const MyStruct2 &_my_struct_2, const int _an_int = -1) :
my_struct_2(_my_struct_2),
an_int(_an_int)
{}
std::string toString() const;
MyStruct2 my_struct_2;
int an_int;
};
The error is:
error C2678: binary '==' : no operator
found which takes a left-hand operand
of type 'myproj::MyStruct1' (or there
is no acceptable conversion)
Why?
In C++, structs do not have a comparison operator generated by default. You need to write your own:
bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return /* your comparison code goes here */
}
C++20 introduced default comparisons, aka the "spaceship" operator<=>, which allows you to request compiler-generated </<=/==/!=/>=/ and/or > operators with the obvious/naive(?) implementation...
auto operator<=>(const MyClass&) const = default;
...but you can customise that for more complicated situations (discussed below). See here for the language proposal, which contains justifications and discussion. This answer remains relevant for C++17 and earlier, and for insight in to when you should customise the implementation of operator<=>....
It may seem a bit unhelpful of C++ not to have already Standardised this earlier, but often structs/classes have some data members to exclude from comparison (e.g. counters, cached results, container capacity, last operation success/error code, cursors), as well as decisions to make about myriad things including but not limited to:
which fields to compare first, e.g. comparing a particular int member might eliminate 99% of unequal objects very quickly, while a map<string,string> member might often have identical entries and be relatively expensive to compare - if the values are loaded at runtime, the programmer may have insights the compiler can't possibly
in comparing strings: case sensitivity, equivalence of whitespace and separators, escaping conventions...
precision when comparing floats/doubles
whether NaN floating point values should be considered equal
comparing pointers or pointed-to-data (and if the latter, how to know how whether the pointers are to arrays and of how many objects/bytes needing comparison)
whether order matters when comparing unsorted containers (e.g. vector, list), and if so whether it's ok to sort them in-place before comparing vs. using extra memory to sort temporaries each time a comparison is done
how many array elements currently hold valid values that should be compared (is there a size somewhere or a sentinel?)
which member of a union to compare
normalisation: for example, date types may allow out-of-range day-of-month or month-of-year, or a rational/fraction object may have 6/8ths while another has 3/4ers, which for performance reasons they correct lazily with a separate normalisation step; you may have to decide whether to trigger a normalisation before comparison
what to do when weak pointers aren't valid
how to handle members and bases that don't implement operator== themselves (but might have compare() or operator< or str() or getters...)
what locks must be taken while reading/comparing data that other threads may want to update
So, it's kind of nice to have an error until you've explicitly thought about what comparison should mean for your specific structure, rather than letting it compile but not give you a meaningful result at run-time.
All that said, it'd be good if C++ let you say bool operator==() const = default; when you'd decided a "naive" member-by-member == test was ok. Same for !=. Given multiple members/bases, "default" <, <=, >, and >= implementations seem hopeless though - cascading on the basis of order of declaration's possible but very unlikely to be what's wanted, given conflicting imperatives for member ordering (bases being necessarily before members, grouping by accessibility, construction/destruction before dependent use). To be more widely useful, C++ would need a new data member/base annotation system to guide choices - that would be a great thing to have in the Standard though, ideally coupled with AST-based user-defined code generation... I expect it'll happen one day.
Typical implementation of equality operators
A plausible implementation
It's likely that a reasonable and efficient implementation would be:
inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return lhs.my_struct2 == rhs.my_struct2 &&
lhs.an_int == rhs.an_int;
}
Note that this needs an operator== for MyStruct2 too.
Implications of this implementation, and alternatives, are discussed under the heading Discussion of specifics of your MyStruct1 below.
A consistent approach to ==, <, > <= etc
It's easy to leverage std::tuple's comparison operators to compare your own class instances - just use std::tie to create tuples of references to fields in the desired order of comparison. Generalising my example from here:
inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return std::tie(lhs.my_struct2, lhs.an_int) ==
std::tie(rhs.my_struct2, rhs.an_int);
}
inline bool operator<(const MyStruct1& lhs, const MyStruct1& rhs)
{
return std::tie(lhs.my_struct2, lhs.an_int) <
std::tie(rhs.my_struct2, rhs.an_int);
}
// ...etc...
When you "own" (i.e. can edit, a factor with corporate and 3rd party libs) the class you want to compare, and especially with C++14's preparedness to deduce function return type from the return statement, it's often nicer to add a "tie" member function to the class you want to be able to compare:
auto tie() const { return std::tie(my_struct1, an_int); }
Then the comparisons above simplify to:
inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return lhs.tie() == rhs.tie();
}
If you want a fuller set of comparison operators, I suggest boost operators (search for less_than_comparable). If it's unsuitable for some reason, you may or may not like the idea of support macros (online):
#define TIED_OP(STRUCT, OP, GET_FIELDS) \
inline bool operator OP(const STRUCT& lhs, const STRUCT& rhs) \
{ \
return std::tie(GET_FIELDS(lhs)) OP std::tie(GET_FIELDS(rhs)); \
}
#define TIED_COMPARISONS(STRUCT, GET_FIELDS) \
TIED_OP(STRUCT, ==, GET_FIELDS) \
TIED_OP(STRUCT, !=, GET_FIELDS) \
TIED_OP(STRUCT, <, GET_FIELDS) \
TIED_OP(STRUCT, <=, GET_FIELDS) \
TIED_OP(STRUCT, >=, GET_FIELDS) \
TIED_OP(STRUCT, >, GET_FIELDS)
...that can then be used a la...
#define MY_STRUCT_FIELDS(X) X.my_struct2, X.an_int
TIED_COMPARISONS(MyStruct1, MY_STRUCT_FIELDS)
(C++14 member-tie version here)
Discussion of specifics of your MyStruct1
There are implications to the choice to provide a free-standing versus member operator==()...
Freestanding implementation
You have an interesting decision to make. As your class can be implicitly constructed from a MyStruct2, a free-standing / non-member bool operator==(const MyStruct2& lhs, const MyStruct2& rhs) function would support...
my_MyStruct2 == my_MyStruct1
...by first creating a temporary MyStruct1 from my_myStruct2, then doing the comparison. This would definitely leave MyStruct1::an_int set to the constructor's default parameter value of -1. Depending on whether you include an_int comparison in the implementation of your operator==, a MyStruct1 might or might not compare equal to a MyStruct2 that itself compares equal to the MyStruct1's my_struct_2 member! Further, creating a temporary MyStruct1 can be a very inefficient operation, as it involves copying the existing my_struct2 member to a temporary, only to throw it away after the comparison. (Of course, you could prevent this implicit construction of MyStruct1s for comparison by making that constructor explicit or removing the default value for an_int.)
Member implementation
If you want to avoid implicit construction of a MyStruct1 from a MyStruct2, make the comparison operator a member function:
struct MyStruct1
{
...
bool operator==(const MyStruct1& rhs) const
{
return tie() == rhs.tie(); // or another approach as above
}
};
Note the const keyword - only needed for the member implementation - advises the compiler that comparing objects doesn't modify them, so can be allowed on const objects.
Comparing the visible representations
Sometimes the easiest way to get the kind of comparison you want can be...
return lhs.to_string() == rhs.to_string();
...which is often very expensive too - those strings painfully created just to be thrown away! For types with floating point values, comparing visible representations means the number of displayed digits determines the tolerance within which nearly-equal values are treated as equal during comparison.
You need to explicitly define operator == for MyStruct1.
struct MyStruct1 {
bool operator == (const MyStruct1 &rhs) const
{ /* your logic for comparision between "*this" and "rhs" */ }
};
Now the == comparison is legal for 2 such objects.
Starting in C++20, it should be possible to add a full set of default comparison operators (==, <=, etc.) to a class by declaring a default three-way comparison operator ("spaceship" operator), like this:
struct Point {
int x;
int y;
auto operator<=>(const Point&) const = default;
};
With a compliant C++20 compiler, adding that line to MyStruct1 and MyStruct2 may be enough to allow equality comparisons, assuming the definition of MyStruct2 is compatible.
By default structs do not have a == operator. You'll have to write your own implementation:
bool MyStruct1::operator==(const MyStruct1 &other) const {
... // Compare the values, and return a bool result.
}
Comparison doesn't work on structs in C or C++. Compare by fields instead.
Out of the box, the == operator only works for primitives. To get your code to work, you need to overload the == operator for your struct.
Because you did not write a comparison operator for your struct. The compiler does not generate it for you, so if you want comparison, you have to write it yourself.
I realize this is a basic question but I have searched online, been to cplusplus.com, read through my book, and I can't seem to grasp the concept of overloaded operators. A specific example from cplusplus.com is:
// vectors: overloading operators example
#include <iostream>
using namespace std;
class CVector {
public:
int x,y;
CVector () {};
CVector (int,int);
CVector operator + (CVector);
};
CVector::CVector (int a, int b) {
x = a;
y = b;
}
CVector CVector::operator+ (CVector param) {
CVector temp;
temp.x = x + param.x;
temp.y = y + param.y;
return (temp);
}
int main () {
CVector a (3,1);
CVector b (1,2);
CVector c;
c = a + b;
cout << c.x << "," << c.y;
return 0;
}
From http://www.cplusplus.com/doc/tutorial/classes2/ but reading through it I'm still not understanding them at all. I just need a basic example of the point of the overloaded operator (which I assume is the "CVector CVector::operator+ (CVector param)").
There's also this example from wikipedia:
Time operator+(const Time& lhs, const Time& rhs)
{
Time temp = lhs;
temp.seconds += rhs.seconds;
if (temp.seconds >= 60)
{
temp.seconds -= 60;
temp.minutes++;
}
temp.minutes += rhs.minutes;
if (temp.minutes >= 60)
{
temp.minutes -= 60;
temp.hours++;
}
temp.hours += rhs.hours;
return temp;
}
From "http://en.wikipedia.org/wiki/Operator_overloading"
The current assignment I'm working on I need to overload a ++ and a -- operator.
Thanks in advance for the information and sorry about the somewhat vague question, unfortunately I'm just not sure on it at all.
Operator overloading is the technique that C++ provides to let you define how the operators in the language can be applied to non-built in objects.
In you example for the Time class operator overload for the + operator:
Time operator+(const Time& lhs, const Time& rhs);
With that overload, you can now perform addition operations on Time objects in a 'natural' fashion:
Time t1 = some_time_initializer;
Time t2 = some_other_time_initializer;
Time t3 = t1 + t2; // calls operator+( t1, t2)
The overload for an operator is just a function with the special name "operator" followed by the symbol for the operator being overloaded. Most operators can be overloaded - ones that cannot are:
. .* :: and ?:
You can call the function directly by name, but usually don't (the point of operator overloading is to be able to use the operators normally).
The overloaded function that gets called is determined by normal overload resolution on the arguments to the operator - that's how the compiler knows to call the operator+() that uses the Time argument types from the example above.
One additional thing to be aware of when overloading the ++ and -- increment and decrement operators is that there are two versions of each - the prefix and the postfix forms. The postfix version of these operators takes an extra int parameter (which is passed 0 and has no purpose other than to differentiate between the two types of operator). The C++ standard has the following examples:
class X {
public:
X& operator++(); //prefix ++a
X operator++(int); //postfix a++
};
class Y { };
Y& operator++(Y&); //prefix ++b
Y operator++(Y&, int); //postfix b++
You should also be aware that the overloaded operators do not have to perform operations that are similar to the built in operators - being more or less normal functions they can do whatever you want. For example, the standard library's IO stream interface uses the shift operators for output and input to/from streams - which is really nothing like bit shifting. However, if you try to be too fancy with your operator overloads, you'll cause much confusion for people who try to follow your code (maybe even you when you look at your code later).
Use operator overloading with care.
An operator in C++ is just a function with a special name. So instead of saying Add(int,int) you say operator +(int,int).
Now as any other function, you can overload it to say work on other types. In your vector example, if you overload operator + to take CVector arguments (ie. operator +(CVector, CVector)), you can then say:
CVector a,b,res;
res=a+b;
Since ++ and -- are unary (they take only one argument), to overload them you'd do like:
type operator ++(type p)
{
type res;
res.value++;
return res;
}
Where type is any type that has a field called value. You get the idea.
What you found in those references are not bad examples of when you'd want operator overloading (giving meaning to vector addition, for example), but they're horrible code when it comes down to the details.
For example, this is much more realistic, showing delegating to the compound assignment operator and proper marking of a const member function:
class Vector2
{
double m_x, m_y;
public:
Vector2(double x, double y) : m_x(x), m_y(y) {}
// Vector2(const Vector2& other) = default;
// Vector2& operator=(const Vector2& other) = default;
Vector2& operator+=(const Vector2& addend) { m_x += addend.m_x; m_y += addend.m_y; return *this; }
Vector2 operator+(const Vector2& addend) const { Vector2 sum(*this); return sum += addend; }
};
From your comments above, you dont see the point of all this operator overloading?
Operator overloading is simply 'syntactic sugar' hiding a method call, and making code somehwhat clearer in many cases.
Consider a simple Integer class wrapping an int. You would write add and other arithmetic methods, possibly increment and decrement as well, requiring a method call such as my_int.add(5). now renaming the add method to operator+ allows my_int + 5, which is more intuitive and clearer, cleaner code. But all it is really doing is hiding a call to your operator+ (renamed add?) method.
Things do get a bit more complex though, as operator + for numbers is well understood by everyone above 2nd grade. But as in the string example above, operators should usually only be applied where they have an intuitive meaning. The Apples example is a good example of where NOT to overload operators.
But applied to say, a List class, something like myList + anObject, should be intuitively understood as 'add anObject to myList', hence the use of the + operator. And operator '-' as meaning 'Removal from the list'.
As I said above, the point of all this is to make code (hopefully) clearer, as in the List example, which would you rather code? (and which do you find easier to read?) myList.add( anObject ) or myList + onObject? But in the background, a method (your implementation of operator+, or add) is being called either way. You can almost think of the compiler rewritting the code: my_int + 5 would become my_int.operator+(5)
All the examples given, such as Time and Vector classes, all have intuitive definitions for the operators. Vector addition... again, easier to code (and read) v1 = v2 + v3 than v1 = v2.add(v3). This is where all the caution you are likely to read regarding not going overboard with operators in your classes, because for most they just wont make sense. But of course there is nothing stopping you putting an operator & into a class like Apple, just dont expect others to know what it does without seeing the code for it!
'Overloading' the operator simply means your are supplying the compiler with another definition for that operator, applied to instances of your class. Rather like overloading methods, same name... different parameters...
Hope this helps...
The "operator" in this case is the + symbol.
The idea here is that an operator does something. An overloaded operator does something different.
So, in this case, the '+' operator, normally used to add two numbers, is being "overloaded" to allow for adding vectors or time.
EDIT: Adding two integers is built-in to c++; the compiler automatically understands what you mean when you do
int x, y = 2, z = 2;
x = y + z;
Objects, on the other hand, can be anything, so using a '+' between two objects doesn't inherently make any sense. If you have something like
Apple apple1, apple2, apple3;
apple3 = apple1 + apple2;
What does it mean when you add two Apple objects together? Nothing, until you overload the '+' operator and tell the compiler what it is that you mean when you add two Apple objects together.
An overloaded operator is when you use an operator to work with types that C++ doesn't "natively" support for that operator.
For example, you can typically use the binary "+" operator to add numeric values (floats, ints, doubles, etc.). You can also add an integer type to a pointer - for instance:
char foo[] = "A few words";
char *p = &(foo[3]); // Points to "e"
char *q = foo + 3; // Also points to "e"
But that's it! You can't do any more natively with a binary "+" operator.
However, operator overloading lets you do things the designers of C++ didn't build into the language - like use the + operator to concatenate strings - for instance:
std::string a("A short"), b(" string.");
std::string c = a + b; // c is "A short string."
Once you wrap your head around that, the Wikipedia examples will make more sense.
A operator would be "+", "-" or "+=". These perform different methods on existing objects. This in fact comes down to a method call. Other than normal method calls these look much more natural to a human user. Writing "1 + 2" just looks more normal and is shorter than "add(1,2)". If you overload an operator, you change the method it executes.
In your first example, the "+" operator's method is overloaded, so that you can use it for vector-addition.
I would suggest that you copy the first example into an editor and play a little around with it. Once you understand what the code does, my suggestion would be to implement vector subtraction and multiplication.
Before starting out, there are many operators out there! Here is a list of all C++ operators: list.
With this being said, operator overloading in C++ is a way to make a certain operator behave in a particular way for an object.
For example, if you use the increment/decrement operators (++ and --) on an object, the compiler will not understand what needs to be incremented/decremented in the object because it is not a primitive type (int, char, float...). You must define the appropriate behavior for the compiler to understand what you mean. Operator overloading basically tells the compiler what must be accomplished when the increment/decrement operators are used with the object.
Also, you must pay attention to the fact that there is postfix incrementing/decrementing and prefix incrementing/decrementing which becomes very important with the notion of iterators and you should note that the syntax for overloading these two type of operators is different from each other. Here is how you can overload these operators: Overloading the increment and decrement operators
The accepted answer by Michael Burr is quite good in explaining the technique, but from the comments it seems that besides the 'how' you are interested in the 'why'. The main reasons to provide operator overloads for a given type are improving readability and providing a required interface.
If you have a type for which there is a single commonly understood meaning for an operator in the domain of your problem, then providing that as an operator overload makes code more readable:
std::complex<double> a(1,2), b(3,4), c( 5, 6 );
std::complex<double> d = a + b + c; // compare to d = a.add(b).add(c);
std::complex<double> e = (a + d) + (b + c); // e = a.add(d).add( b.add(c) );
If your type has a given property that will naturally be expressed with an operator, you can overload that particular operator for your type. Consider for example, that you want to compare your objects for equality. Providing operator== (and operator!=) can give you a simple readable way of doing so. This has the advantage of fulfilling a common interface that can be used with algorithms that depend on equality:
struct type {
type( int x ) : value(x) {}
int value;
};
bool operator==( type const & lhs, type const & rhs )
{ return lhs.value == rhs.value; }
bool operator!=( type const & lhs, type const & rhs )
{ return !lhs == rhs; }
std::vector<type> getObjects(); // creates and fills a vector
int main() {
std::vector<type> objects = getObjects();
type t( 5 );
std::find( objects.begin(), objects.end(), t );
}
Note that when the find algorithm is implemented, it depends on == being defined. The implementation of find will work with primitive types as well as with any user defined type that has an equality operator defined. There is a common single interface that makes sense. Compare that with the Java version, where comparison of object types must be performed through the .equals member function, while comparing primitive types can be done with ==. By allowing you to overload the operators you can work with user defined types in the same way that you can with primitive types.
The same goes for ordering. If there is a well defined (partial) order in the domain of your class, then providing operator< is a simple way of implementing that order. Code will be readable, and your type will be usable in all situations where a partial order is required, as inside associative containers:
bool operator<( type const & lhs, type const & rhs )
{
return lhs < rhs;
}
std::map<type, int> m; // m will use the natural `operator<` order
A common pitfall when operator overloading was introduced into the language is that of the 'golden hammer' Once you have a golden hammer everything looks like a nail, and operator overloading has been abused.
It is important to note that the reason for overloading in the first place is improving readability. Readability is only improved if when a programmer looks at the code, the intentions of each operation are clear at first glance, without having to read the definitions. When you see that two complex numbers are being added like a + b you know what the code is doing. If the definition of the operator is not natural (you decide to implement it as adding only the real part of it) then code will become harder to read than if you had provided a (member) function. If the meaning of the operation is not well defined for your type the same happens:
MyVector a, b;
MyVector c = a + b;
What is c? Is it a vector where each element i is the sum of of the respective elements from a and b, or is it a vector created by concatenating the elements of a before the elements of b. To understand the code, you would need to go to the definition of the operation, and that means that overloading the operator is less readable than providing a function:
MyVector c = append( a, b );
The set of operators that can be overloaded is not restricted to the arithmetic and relational operators. You can overload operator[] to index into a type, or operator() to create a callable object that can be used as a function (these are called functors) or that will simplify usage of the class:
class vector {
public:
int operator[]( int );
};
vector v;
std::cout << v[0] << std::endl;
class matrix {
public:
int operator()( int row, int column );
// operator[] cannot be overloaded with more than 1 argument
};
matrix m;
std::cout << m( 3,4 ) << std::endl;
There are other uses of operator overloading. In particular operator, can be overloaded in really fancy ways for metaprogramming purposes, but that is probably much more complex than what you really care for now.
Another use of operator overloading, AFAIK unique to C++, is the ability to overload the assignment operator. If you have:
class CVector
{
// ...
private:
size_t capacity;
size_t length;
double* data;
};
void func()
{
CVector a, b;
// ...
a = b;
}
Then a.data and b.data will point to the same location, and if you modify a, you affect b as well. That's probably not what you want. But you can write:
CVector& CVector::operator=(const CVector& rhs)
{
delete[] data;
capacity = length = rhs.length;
data = new double[length];
memcpy(data, rhs.data, length * sizeof(double));
return (*this);
}
and get a deep copy.
Operator overloading allows you to give own meaning to the operator.
For example, consider the following code snippet:
char* str1 = "String1";
char* str2 = "String2";
char str3[20];
str3 = str1 + str2;
You can overload the "+" operator to concatenate two strings. Doesn't this look more programmer-friendly?
Is it possible to make a custom operator so you can do things like this?
if ("Hello, world!" contains "Hello") ...
Note: this is a separate question from "Is it a good idea to..." ;)
Yes! (well, sort of)
There are a couple publicly available tools to help you out. Both use preprocessor code generation to create templates which implement the custom operators. These operators consist of one or more built-in operators in conjunction with an identifier.
Since these aren't actually custom operators, but merely tricks of operator overloading, there are a few caveats:
Macros are evil. If you make a mistake, the compiler will be all but entirely useless for tracking down the problem.
Even if you get the macro right, if there is an error in your usage of the operator or in the definition of your operation, the compiler will be only slightly more helpful.
You must use a valid identifier as part of the operator. If you want a more symbol-like operator, you can use _, o or similarly simple alphanumerics.
CustomOperators
While I was working on my own library for this purpose (see below) I came across this project. Here is an example of creating an avg operator:
#define avg BinaryOperatorDefinition(_op_avg, /)
DeclareBinaryOperator(_op_avg)
DeclareOperatorLeftType(_op_avg, /, double);
inline double _op_avg(double l, double r)
{
return (l + r) / 2;
}
BindBinaryOperator(double, _op_avg, /, double, double)
IdOp
What started as an exercise in pure frivolity became my own take on this problem. Here's a similar example:
template<typename T> class AvgOp {
public:
T operator()(const T& left, const T& right)
{
return (left + right) / 2;
}
};
IDOP_CREATE_LEFT_HANDED(<, _avg_, >, AvgOp)
#define avg <_avg_>
Key Differences
CustomOperators supports postfix unary operators
IdOp templates use references rather than pointers to eliminate use of the free store, and to allow full compile-time evaluation of the operation
IdOp allows you to easily specify several operations for the same root identifier
There's a method thoroughly explored in 'Syntactic Aspartame' by Sander Stoks that would allow you to use the following format:
if ("Hello, world!" <contains> "Hello") ...
In essence, you need a proxy object with the operators '<' and '>' overloaded. The proxy does all of the work; 'contains' can just be a singleton with no behavior or data of its own.
// Not my code!
const struct contains_ {} contains;
template <typename T>
struct ContainsProxy
{
ContainsProxy(const T& t): t_(t) {}
const T& t_;
};
template <typename T>
ContainsProxy<T> operator<(const T& lhs, const contains_& rhs)
{
return ContainsProxy<T>(lhs);
}
bool operator>(const ContainsProxy<Rect>& lhs, const Rect& rhs)
{
return lhs.t_.left <= rhs.left &&
lhs.t_.top <= rhs.top &&
lhs.t_.right >= rhs.right &&
lhs.t_.bottom >= rhs.bottom;
}
I've created the following two macros:
#define define const struct
#define operator(ReturnType, OperatorName, FirstOperandType, SecondOperandType) OperatorName ## _ {} OperatorName; template <typename T> struct OperatorName ## Proxy{public:OperatorName ## Proxy(const T& t) : t_(t){}const T& t_;static ReturnType _ ## OperatorName ## _(const FirstOperandType a, const SecondOperandType b);};template <typename T> OperatorName ## Proxy<T> operator<(const T& lhs, const OperatorName ## _& rhs){return OperatorName ## Proxy<T>(lhs);}ReturnType operator>(const OperatorName ## Proxy<FirstOperandType>& lhs, const SecondOperandType& rhs){return OperatorName ## Proxy<FirstOperandType>::_ ## OperatorName ## _(lhs.t_, rhs);}template <typename T> inline ReturnType OperatorName ## Proxy<T>::_ ## OperatorName ## _(const FirstOperandType a, const SecondOperandType b)
Then, you'd have just to define your custom operator as in the following example:
define operator(bool, myOr, bool, bool) { // Arguments are the return type, the name of the operator, the left operand type and the right operand type, respectively
return a || b;
}
#define myOr <myOr> // Finally, you have to define a macro to avoid to put the < and > operator at the start and end of the operator name
Once a time you've set your operator up, you can use it as a predefined operator:
bool a = true myOr false;
// a == true
Warning
While this has been an interesting exercise, it merely demonstrates how bad is to have a macro–enabled precompiler. Adding custom operators like this can easily lead to a sort of metalanguage. Although we know how badly is C++ designed (most of all considering that it was first conceived as a set of extensions for C), we shouldn't be changing it. If you can't use standard C++, which is the only way to keep the code understandable by other people, you should just switch to another language that makes what you wish to do the way you'd like. There are thousands languages — no need to mess around with C++ to make it different.
SHORTLY: You just shouldn't be using this code. You should refrain from using macros unless when only used the same way as inline methods.
To be a bit more accurate, C++ itself only supports creating new overloads of existing operations, NOT creating new operators. There are languages (e.g., ML and most of its descendants) that do allow you to create entirely new operators, but C++ is not one of them.
From the looks of things, (at least) the CustomOperators library mentioned in the other answer doesn't support entirely custom operators either. At least if I'm reading things correctly, it's (internally) translating your custom operator into an overload of an existing operator. That makes things easier, at the expense of some flexibility -- for example, when you create a new operator in ML, you can give it precedence different from that of any built-in operator.
Technically, no. That is to say, you can't extend the set of operator+, operator-, etcetera. But what you're proposing in your example is something else. You are wondering if there is a definition of "contains" such that string-literal "contains" string-literal is an expression, with non-trivial logic (#define contains "" being the trivial case).
There are not many expressions that can have the form string-literal X string-literal. This is because string literals themselves are expressions. So, you're looking for a language rule of the form expr X expr. There are quite a few of those, but they're all rules for operators, and those don't work on strings. Despite the obvious implementation, "Hello, " + "world" is not a valid expression. So, what else can X be in string-literal X string-literal ? It can't be a expression itself. It can't be a typename, a typedef name or a template name. It can't be a function name. It can really only be a macro, which are the only remaining named entities. For that, see the "Yes (well, sort of)" answer.
As others have pointed out you sadly can not write custom operators but with macros you can get similar behaviour. It is actually really easy with c style casting see below.
class To_Range{
public:
size_t start;
size_t end;
To_Range(size_t _start,size_t _end) :
start(_start), end(_end) {}
};
class Slicing_To_End{
public:
int end;
Slicing_To_End(const int& init) : end(init) {}
};
To_Range operator == (const int& start,const Slicing_To_End& end) {
return To_Range(start,end.end);
}
#define to == (Slicing_To_End)
Here 4 to 5 will give back an object of type To_Range. (Slicing_To_End) casts 5 to Slicing_To_End. Now the compiler wants to find an == operator that fits. The only one is our custom operator that takes as input an integer on the first position and in the second Slicing_To_End and returns our type To_Range. You also could return of course other types like int,float.
Your suggestion would be nothing more than syntactic sugar for:
if( contains( "Hello, world!", "Hello" ) ...
and in fact there are already a functions to do that in both cstring and std::string. Which is perhaps a bit like answering "is it a good idea?" but not quite; rather asking "why would you need/want to?"