{"id":201,"date":"2008-04-29T20:14:19","date_gmt":"2008-04-30T04:14:19","guid":{"rendered":"http:\/\/www.learncpp.com\/?p=201"},"modified":"2023-09-11T12:40:44","modified_gmt":"2023-09-11T19:40:44","slug":"overloading-operators-and-function-templates","status":"publish","type":"post","link":"https:\/\/www.learncpp.com\/cpp-tutorial\/overloading-operators-and-function-templates\/","title":{"rendered":"21.14 &#8212; Overloading operators and function templates"},"content":{"rendered":"<p>In lesson <a href=\"https:\/\/www.learncpp.com\/cpp-tutorial\/function-template-instantiation\/\">11.7 -- Function template instantiation<\/a>, we discussed how the compiler will use function templates to instantiate functions, which are then compiled.  We also noted that these functions may not compile, if the code in the function template tries to perform some operation that the actual type doesn&#8217;t support (such as adding integer value <code>1<\/code> to a <code>std::string<\/code>).<\/p>\n<p>In this lesson, we&#8217;ll take a look at a few examples where our instantiated functions won&#8217;t compile because our actual class types don&#8217;t support those operators, and show how we can define those operators so that the instantiated functions will then compile.<\/p>\n<p class=\"cpp-section cpp-topline\" style=\"clear: both\">Operators, function calls, and function templates<\/p>\n<p>First, let&#8217;s create a simple class:<\/p>\n<pre class=\"language-cpp line-numbers\"><code class=\"language-cpp match-braces\">class Cents\r\n{\r\nprivate:\r\n    int m_cents{};\r\npublic:\r\n    Cents(int cents)\r\n        : m_cents { cents }\r\n    {\r\n    }\r\n\r\n    friend std::ostream&amp; operator&lt;&lt; (std::ostream&amp; ostr, const Cents&amp; c)\r\n    {\r\n        ostr &lt;&lt; c.m_cents;\r\n        return ostr;\r\n    }\r\n};<\/code><\/pre>\n<p>and define a <code>max<\/code> function template:<\/p>\n<pre class=\"language-cpp line-numbers\"><code class=\"language-cpp match-braces\">template &lt;typename T&gt;\r\nconst T&amp; max(const T&amp; x, const T&amp; y)\r\n{\r\n    return (x &lt; y) ? y : x;\r\n}<\/code><\/pre>\n<p>Now, let&#8217;s see what happens when we try to call <code>max()<\/code> with object of type <code>Cents<\/code>:<\/p>\n<pre class=\"language-cpp line-numbers\"><code class=\"language-cpp match-braces\">#include &lt;iostream&gt;\r\n\r\nclass Cents\r\n{\r\nprivate:\r\n    int m_cents{};\r\npublic:\r\n    Cents(int cents)\r\n        : m_cents { cents }\r\n    {\r\n    }\r\n\r\n    friend std::ostream&amp; operator&lt;&lt; (std::ostream&amp; ostr, const Cents&amp; c)\r\n    {\r\n        ostr &lt;&lt; c.m_cents;\r\n        return ostr;\r\n    }\r\n};\r\n\r\ntemplate &lt;typename T&gt;\r\nconst T&amp; max(const T&amp; x, const T&amp; y)\r\n{\r\n    return (x &lt; y) ? y : x;\r\n}\r\n\r\nint main()\r\n{\r\n    Cents nickel{ 5 };\r\n    Cents dime{ 10 };\r\n\r\n    Cents bigger { max(nickel, dime) };\r\n    std::cout &lt;&lt; bigger &lt;&lt; \" is bigger\\n\";\r\n\r\n    return 0;\r\n}<\/code><\/pre>\n<p>C++ will create a template instance for max() that looks like this:<\/p>\n<pre class=\"language-cpp line-numbers\"><code class=\"language-cpp match-braces\">template &lt;&gt;\r\nconst Cents&amp; max(const Cents&amp; x, const Cents&amp; y)\r\n{\r\n    return (x &lt; y) ? y : x;\r\n}<\/code><\/pre>\n<p>And then it will try to compile this function.  See the problem here?  C++ has no idea how to evaluate <code>x &lt; y<\/code> when <code>x<\/code> and <code>y<\/code> are of type <code>Cents<\/code>!  Consequently, this will produce a compile error.<\/p>\n<p>To get around this problem, simply overload <code>operator&lt;<\/code> for any class we wish to use <code>max<\/code> with:<\/p>\n<pre class=\"language-cpp line-numbers\"><code class=\"language-cpp match-braces\">#include &lt;iostream&gt;\r\n\r\nclass Cents\r\n{\r\nprivate:\r\n    int m_cents {};\r\npublic:\r\n    Cents(int cents)\r\n        : m_cents { cents }\r\n    {\r\n    }\r\n    \r\n    friend bool operator&lt; (const Cents&amp; c1, const Cents&amp; c2)\r\n    {\r\n        return (c1.m_cents &lt; c2.m_cents);\r\n    }\r\n\r\n    friend std::ostream&amp; operator&lt;&lt; (std::ostream&amp; ostr, const Cents&amp; c)\r\n    {\r\n        ostr &lt;&lt; c.m_cents;\r\n        return ostr;\r\n    }\r\n};\r\n\r\ntemplate &lt;typename T&gt;\r\nconst T&amp; max(const T&amp; x, const T&amp; y)\r\n{\r\n    return (x &lt; y) ? y : x;\r\n}\r\n\r\nint main()\r\n{\r\n    Cents nickel{ 5 };\r\n    Cents dime { 10 };\r\n\r\n    Cents bigger { max(nickel, dime) };\r\n    std::cout &lt;&lt; bigger &lt;&lt; \" is bigger\\n\";\r\n\r\n    return 0;\r\n}<\/code><\/pre>\n<p>This works as expected, and prints:<\/p>\n<pre>\r\n10 is bigger\r\n<\/pre>\n<p class=\"cpp-section cpp-topline\" style=\"clear: both\">Another example<\/p>\n<p>Let&#8217;s do one more example of a function template not working because of missing overloaded operators.<\/p>\n<p>The following function template will calculate the average of a number of objects in an array:<\/p>\n<pre class=\"language-cpp line-numbers\"><code class=\"language-cpp match-braces\">#include &lt;iostream&gt;\r\n\r\ntemplate &lt;typename T&gt;\r\nT average(const T* myArray, int numValues)\r\n{\r\n    T sum { 0 };\r\n    for (int count { 0 }; count &lt; numValues; ++count)\r\n        sum += myArray[count];\r\n\r\n    sum \/= numValues;\r\n    return sum;\r\n}\r\n\r\nint main()\r\n{\r\n    int intArray[] { 5, 3, 2, 1, 4 };\r\n    std::cout &lt;&lt; average(intArray, 5) &lt;&lt; '\\n';\r\n\r\n    double doubleArray[] { 3.12, 3.45, 9.23, 6.34 };\r\n    std::cout &lt;&lt; average(doubleArray, 4) &lt;&lt; '\\n';\r\n\r\n    return 0;\r\n}<\/code><\/pre>\n<p>This produces the values:<\/p>\n<pre>\r\n3\r\n5.535\r\n<\/pre>\n<p>As you can see, it works great for built-in types!<\/p>\n<p>Now let&#8217;s see what happens when we call this function on our <code>Cents<\/code> class:<\/p>\n<pre class=\"language-cpp line-numbers\"><code class=\"language-cpp match-braces\">#include &lt;iostream&gt;\r\n\r\ntemplate &lt;typename T&gt;\r\nT average(const T* myArray, int numValues)\r\n{\r\n    T sum { 0 };\r\n    for (int count { 0 }; count &lt; numValues; ++count)\r\n        sum += myArray[count];\r\n\r\n    sum \/= numValues;\r\n    return sum;\r\n}\r\n\r\nclass Cents\r\n{\r\nprivate:\r\n    int m_cents {};\r\npublic:\r\n    Cents(int cents)\r\n        : m_cents { cents }\r\n    {\r\n    }\r\n};\r\n\r\nint main()\r\n{\r\n    Cents centsArray[] { Cents { 5 }, Cents { 10 }, Cents { 15 }, Cents { 14 } };\r\n    std::cout &lt;&lt; average(centsArray, 4) &lt;&lt; '\\n';\r\n\r\n    return 0;\r\n}<\/code><\/pre>\n<p>The compiler goes berserk and produces a ton of error messages!  The first error message will be something like this:<\/p>\n<pre>\r\nerror C2679: binary &lt;&lt; : no operator found which takes a right-hand operand of type Cents (or there is no acceptable conversion)\r\n<\/pre>\n<p>Remember that <code>average()<\/code> returns a <code>Cents<\/code> object, and we are trying to stream that object to <code>std::cout<\/code> using <code>operator&lt;&lt;<\/code>.  However, we haven&#8217;t defined the <code>operator&lt;&lt;<\/code> for our <code>Cents<\/code> class yet.  Let&#8217;s do that:<\/p>\n<pre class=\"language-cpp line-numbers\"><code class=\"language-cpp match-braces\">#include &lt;iostream&gt;\r\n\r\ntemplate &lt;typename T&gt;\r\nT average(const T* myArray, int numValues)\r\n{\r\n    T sum { 0 };\r\n    for (int count { 0 }; count &lt; numValues; ++count)\r\n        sum += myArray[count];\r\n\r\n    sum \/= numValues;\r\n    return sum;\r\n}\r\n\r\nclass Cents\r\n{\r\nprivate:\r\n    int m_cents {};\r\npublic:\r\n    Cents(int cents)\r\n        : m_cents { cents }\r\n    {\r\n    }\r\n\r\n    friend std::ostream&amp; operator&lt;&lt; (std::ostream&amp; out, const Cents&amp; cents)\r\n    {\r\n        out &lt;&lt; cents.m_cents &lt;&lt; \" cents \";\r\n        return out;\r\n    }\r\n};\r\n\r\nint main()\r\n{\r\n    Cents centsArray[] { Cents { 5 }, Cents { 10 }, Cents { 15 }, Cents { 14 } };\r\n    std::cout &lt;&lt; average(centsArray, 4) &lt;&lt; '\\n';\r\n\r\n    return 0;\r\n}<\/code><\/pre>\n<p>If we compile again, we will get another error:<\/p>\n<pre>error C2676: binary += : Cents does not define this operator or a conversion to a type acceptable to the predefined operator<\/pre>\n<p>This error is actually being caused by the function template instance created when we call <code>average(const Cents*, int)<\/code>.  Remember that when we call a templated function, the compiler &#8220;stencils&#8221; out a copy of the function where the template type parameters (the placeholder types) have been replaced with the actual types in the function call.  Here is the function template instance for <code>average()<\/code> when <code>T<\/code> is a <code>Cents<\/code> object:<\/p>\n<pre class=\"language-cpp line-numbers\"><code class=\"language-cpp match-braces\">template &lt;&gt;\r\nCents average(const Cents* myArray, int numValues)\r\n{\r\n    Cents sum { 0 };\r\n    for (int count { 0 }; count &lt; numValues; ++count)\r\n        sum += myArray[count];\r\n\r\n    sum \/= numValues;\r\n    return sum;\r\n}<\/code><\/pre>\n<p>The reason we are getting an error message is because of the following line:<\/p>\n<pre class=\"language-cpp line-numbers\"><code class=\"language-cpp match-braces\">        sum += myArray[count];<\/code><\/pre>\n<p>In this case, <code>sum<\/code> is a <code>Cents<\/code> object, but we have not defined <code>operator+=<\/code> for <code>Cents<\/code> objects!  We will need to define this function in order for <code>average()<\/code> to be able to work with <code>Cents<\/code>.  Looking forward, we can see that <code>average()<\/code> also uses the <code>operator\/=<\/code>, so we will go ahead and define that as well:<\/p>\n<pre class=\"language-cpp line-numbers\"><code class=\"language-cpp match-braces\">#include &lt;iostream&gt;\r\n\r\ntemplate &lt;typename T&gt;\r\nT average(const T* myArray, int numValues)\r\n{\r\n    T sum { 0 };\r\n    for (int count { 0 }; count &lt; numValues; ++count)\r\n        sum += myArray[count];\r\n\r\n    sum \/= numValues;\r\n    return sum;\r\n}\r\n\r\nclass Cents\r\n{\r\nprivate:\r\n    int m_cents {};\r\npublic:\r\n    Cents(int cents)\r\n        : m_cents { cents }\r\n    {\r\n    }\r\n\r\n    friend std::ostream&amp; operator&lt;&lt; (std::ostream&amp; out, const Cents&amp; cents)\r\n    {\r\n        out &lt;&lt; cents.m_cents &lt;&lt; \" cents \";\r\n        return out;\r\n    }\r\n\r\n    Cents&amp; operator+= (const Cents &amp;cents)\r\n    {\r\n        m_cents += cents.m_cents;\r\n        return *this;\r\n    }\r\n\r\n    Cents&amp; operator\/= (int x)\r\n    {\r\n        m_cents \/= x;\r\n        return *this;\r\n    }\r\n};\r\n\r\nint main()\r\n{\r\n    Cents centsArray[] { Cents { 5 }, Cents { 10 }, Cents { 15 }, Cents { 14 } };\r\n    std::cout &lt;&lt; average(centsArray, 4) &lt;&lt; '\\n';\r\n\r\n    return 0;\r\n}<\/code><\/pre>\n<p>Finally, our code will compile and run!  Here is the result:<\/p>\n<pre>\r\n11 cents\r\n<\/pre>\n<p>Note that we didn&#8217;t have to modify <code>average()<\/code> at all to make it work with objects of type <code>Cents<\/code>.  We simply had to define the operators used to implement <code>average()<\/code> for the <code>Cents<\/code> class, and the compiler took care of the rest!<\/p>\n<div class=\"prevnext\"><div class=\"prevnext-inline\">\n\t<a class=\"nav-link\" href=\"https:\/\/www.learncpp.com\/cpp-tutorial\/chapter-21-summary-and-quiz\/\">\n <div class=\"nav-button nav-button-next\">\n    <div class=\"nav-button-icon\"><i class=\"fa fa-chevron-circle-right\" aria-hidden=\"true\"><\/i><\/div>\n    <div class=\"nav-button-text\">\n      <div class=\"nav-button-title\">Next lesson<\/div>\n      <div class=\"nav-button-lesson\">\n        <span class=\"nav-button-lesson-number\">21.x<\/span>Chapter 21 summary and quiz\n      <\/div>\n    <\/div>\n  <\/div><\/a>\n  \t<a class=\"nav-link\" href=\"\/\">\n  <div class=\"nav-button nav-button-index\">\n    <div class=\"nav-button-icon\"><i class=\"fa fa-home\" aria-hidden=\"true\"><\/i><\/div>\n    <div class=\"nav-button-text\">\n      <div class=\"nav-button-title\">Back to table of contents<\/div>\n    <\/div>\n<\/div><\/a>\n  \t<a class=\"nav-link\" href=\"https:\/\/www.learncpp.com\/cpp-tutorial\/shallow-vs-deep-copying\/\">\n  <div class=\"nav-button nav-button-prev\">\n    <div class=\"nav-button-icon\"><i class=\"fa fa-chevron-circle-left\" aria-hidden=\"true\"><\/i><\/div>\n    <div class=\"nav-button-text\">\n      <div class=\"nav-button-title\">Previous lesson<\/div>\n      <div class=\"nav-button-lesson\">\n        <span class=\"nav-button-lesson-number\">21.13<\/span>Shallow vs. deep copying\n      <\/div>\n    <\/div>\n  <\/div><\/a>\n  <\/div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>In lesson , we discussed how the compiler will use function templates to instantiate functions, which are then compiled. We also noted that these functions may not compile, if the code in the function template tries to perform some operation that the actual type doesn&#8217;t support (such as adding integer &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[3],"tags":[12,13,14,17,15,16],"_links":{"self":[{"href":"https:\/\/www.learncpp.com\/wp-json\/wp\/v2\/posts\/201"}],"collection":[{"href":"https:\/\/www.learncpp.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.learncpp.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.learncpp.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.learncpp.com\/wp-json\/wp\/v2\/comments?post=201"}],"version-history":[{"count":37,"href":"https:\/\/www.learncpp.com\/wp-json\/wp\/v2\/posts\/201\/revisions"}],"predecessor-version":[{"id":15354,"href":"https:\/\/www.learncpp.com\/wp-json\/wp\/v2\/posts\/201\/revisions\/15354"}],"wp:attachment":[{"href":"https:\/\/www.learncpp.com\/wp-json\/wp\/v2\/media?parent=201"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.learncpp.com\/wp-json\/wp\/v2\/categories?post=201"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.learncpp.com\/wp-json\/wp\/v2\/tags?post=201"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}