What type does the conversion logic target?












16















I don't understand why in the following code the expression C c3 = 5 + c;
doesn't get compiled although 5 could be converted to type C as in the previous statement.



#include <iostream>

class C
{
int m_value;
public:
C(int value): m_value(value) {} ;

int get_value() { return m_value; } ;

C operator+(C rhs) { return C(rhs.m_value+m_value); }
};

int main()
{
C c = 10;
C c2 = c + 5; // Works fine. 5 is converted to type C and the operator + is called
C c3 = 5 + c; // Not working: compiler error. Question: Why is 5 not converted to type C??

std::cout << c.get_value() << std::endl; // output 10
std::cout << c2.get_value() << std::endl; // output 15

}












share|improve this question




















  • 3





    Create free function C operator+(C lhs, C rhs) instead of member function to allow conversion for both sides.

    – Jarod42
    Feb 13 at 9:28













  • See the docs for example implementations

    – EdChum
    Feb 13 at 9:28
















16















I don't understand why in the following code the expression C c3 = 5 + c;
doesn't get compiled although 5 could be converted to type C as in the previous statement.



#include <iostream>

class C
{
int m_value;
public:
C(int value): m_value(value) {} ;

int get_value() { return m_value; } ;

C operator+(C rhs) { return C(rhs.m_value+m_value); }
};

int main()
{
C c = 10;
C c2 = c + 5; // Works fine. 5 is converted to type C and the operator + is called
C c3 = 5 + c; // Not working: compiler error. Question: Why is 5 not converted to type C??

std::cout << c.get_value() << std::endl; // output 10
std::cout << c2.get_value() << std::endl; // output 15

}












share|improve this question




















  • 3





    Create free function C operator+(C lhs, C rhs) instead of member function to allow conversion for both sides.

    – Jarod42
    Feb 13 at 9:28













  • See the docs for example implementations

    – EdChum
    Feb 13 at 9:28














16












16








16


1






I don't understand why in the following code the expression C c3 = 5 + c;
doesn't get compiled although 5 could be converted to type C as in the previous statement.



#include <iostream>

class C
{
int m_value;
public:
C(int value): m_value(value) {} ;

int get_value() { return m_value; } ;

C operator+(C rhs) { return C(rhs.m_value+m_value); }
};

int main()
{
C c = 10;
C c2 = c + 5; // Works fine. 5 is converted to type C and the operator + is called
C c3 = 5 + c; // Not working: compiler error. Question: Why is 5 not converted to type C??

std::cout << c.get_value() << std::endl; // output 10
std::cout << c2.get_value() << std::endl; // output 15

}












share|improve this question
















I don't understand why in the following code the expression C c3 = 5 + c;
doesn't get compiled although 5 could be converted to type C as in the previous statement.



#include <iostream>

class C
{
int m_value;
public:
C(int value): m_value(value) {} ;

int get_value() { return m_value; } ;

C operator+(C rhs) { return C(rhs.m_value+m_value); }
};

int main()
{
C c = 10;
C c2 = c + 5; // Works fine. 5 is converted to type C and the operator + is called
C c3 = 5 + c; // Not working: compiler error. Question: Why is 5 not converted to type C??

std::cout << c.get_value() << std::endl; // output 10
std::cout << c2.get_value() << std::endl; // output 15

}









c++ operator-overloading






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Feb 13 at 14:45









Boann

37.2k1290121




37.2k1290121










asked Feb 13 at 9:26









Soulimane MammarSoulimane Mammar

476413




476413








  • 3





    Create free function C operator+(C lhs, C rhs) instead of member function to allow conversion for both sides.

    – Jarod42
    Feb 13 at 9:28













  • See the docs for example implementations

    – EdChum
    Feb 13 at 9:28














  • 3





    Create free function C operator+(C lhs, C rhs) instead of member function to allow conversion for both sides.

    – Jarod42
    Feb 13 at 9:28













  • See the docs for example implementations

    – EdChum
    Feb 13 at 9:28








3




3





Create free function C operator+(C lhs, C rhs) instead of member function to allow conversion for both sides.

– Jarod42
Feb 13 at 9:28







Create free function C operator+(C lhs, C rhs) instead of member function to allow conversion for both sides.

– Jarod42
Feb 13 at 9:28















See the docs for example implementations

– EdChum
Feb 13 at 9:28





See the docs for example implementations

– EdChum
Feb 13 at 9:28












3 Answers
3






active

oldest

votes


















3














Here's an additional remark (a bit of a "reductio ad absurdum") on why your suggestion that the compiler could implicitly convert the left hand argument to a C would, essentially, open a can of worms. The actual language rules say, simply put, that, before applying conversions, a name lookup – for function calls and calls to (user-declared) operators – is done to find a candidate set. At this point, the operand types are not yet considered, but the scope very well is. So the type of the first argument does matter insofar as a user-declared operator is only in scope if its first argument is of the (cv-qualified) class type it is declared in. When a candidate set has been found, the compiler then tries to apply the conversion rules and ranks the candidates etc.



(Your question is therefore a bit misleading because in your example, we don't even get to the conversion logic, instead name resolution already comes up empty.)



Now, imagine we could simply change the language to say that the first argument can also be converted, prior to name resolution. A little bit of handwaving is required here, because this means we have to do conversions, look up names, and then do conversions again, so how this would work in practice is certainly unclear. Anyway, look at this example then:



struct B;
struct A
{
A(int);
A operator +(B) const;
};
struct B
{
B(int);
B operator +(B) const;
};


Now, what should 1 + B{3} do? Apparently, it could be transformed to B{1} + B{3}. But who's to say we couldn't do A{1} + B{3} instead? Why would B's constructor be preferred over A's? Of course, we could argue that either B is to be preferred, because, look at how nice and symmetric B{...}+B{...} is (ok, I'm being slightly facetious). Or we could take the safer route of saying that the program is ill-formed if it contains such an ambiguity. But there are a lot more corner cases to consider, e.g. what if B's constructor was made explicit – should the compiler (still or newly) error out, or should it silently switch to the usable implicit conversion to A?



Another non-obvious point is which types in which scopes (e.g. namespaces) should be considered? It would certainly be surprising if you use operator + in e.g. global namespace scope, and the compiler would dig out some type __gnucxx::__internal::__cogwheels::__do_something_impl, implcitly convert an operand to it, and then perform an operation on that.



Also note that this feature even if it can be specified in a reasonable and clean manner, could have quite a compile-time cost (in fact, overload resolution is already one of the biggests costs when compiling C++ and one of the reasons why compiling C++ code can take a lot longer than compiling C).



TL;DR:




  • There are tricky corner cases.

  • The benefit is marginal (why not make such operators free functions as others have pointed out)?

  • The discussions on how to standardize this would certainly be long.






share|improve this answer































    21














    Because if overload operator as member function of the class, it could only be called when the object of that class is used as left operand. (And the left operand becomes the implicit *this object for the member function to be called.)




    Binary operators are typically implemented as non-members to maintain symmetry (for example, when adding a complex number and an integer, if operator+ is a member function of the complex type, then only complex+integer would compile, and not integer+complex).




    From the standard, [over.match.oper]/3



    (emphasis mine)




    For a unary operator @ with an operand of a type whose cv-unqualified
    version is T1, and for a binary operator @ with a left operand of a
    type whose cv-unqualified version is T1 and a right operand of a type
    whose cv-unqualified version is T2, four sets of candidate functions,
    designated member candidates, non-member candidates, built-in
    candidates, and rewritten candidates, are constructed as follows:




    • (3.1) If T1 is a complete class type or a class currently being defined, the set of member candidates is the result of the qualified
      lookup of T1::operator@ ([over.call.func]); otherwise, the set of
      member candidates is empty
      .




    That means if the type of left operand is not a class type, the set of member candidates is empty; the overloaded operator (as member function) won't be considered.



    You can overload it as a non-member function to allow the implicit conversion for both left and right operands.



    C operator+(C lhs, C rhs) { return C(lhs.get_value() + rhs.get_value()); }


    then both c + 5 or 5 + c would work fine.



    LIVE



    BTW: This will cause one temporaray object being constructed (from int to C) for the non-member function to be called; if you care about that, you can add all the three possible overloads as follows. Also note that this is a trade-off issue.



    C operator+(C lhs, C rhs) { return C(lhs.get_value() + rhs.get_value()); }
    C operator+(C lhs, int rhs) { return C(lhs.get_value() + rhs); }
    C operator+(int lhs, C rhs) { return C(lhs + rhs.get_value()); }


    And here're some suggestions about when to use a normal, friend, or member function overload.




    In most cases, the language leaves it up to you to determine whether
    you want to use the normal/friend or member function version of the
    overload. However, one of the two is usually a better choice than the
    other.



    When dealing with binary operators that don’t modify the left operand
    (e.g. operator+), the normal or friend function version is typically
    preferred, because it works for all parameter types (even when the
    left operand isn’t a class object, or is a class that is not
    modifiable). The normal or friend function version has the added
    benefit of “symmetry”, as all operands become explicit parameters
    (instead of the left operand becoming *this and the right operand
    becoming an explicit parameter).



    When dealing with binary operators that do modify the left operand
    (e.g. operator+=), the member function version is typically preferred.
    In these cases, the leftmost operand will always be a class type, and
    having the object being modified become the one pointed to by *this is
    natural. Because the rightmost operand becomes an explicit parameter,
    there’s no confusion over who is getting modified and who is getting
    evaluated.







    share|improve this answer

































      8














      You are facing the reason to define certain operator overloads as free functions, i.e., when implicit conversions are desired. To see what's going on under the hood, consider the verbose form of operator overload invocations:



      C c2 = c.operator+(5); // Ok, c has this member function
      C c3 = 5.operator+(c); // No way, this is an integer without members


      You can obviously do is an explicit C construction as in



      C c3 = C{5} + c;


      but this is not intended for an arithmetic value type like C. To make the implicit construction possible, define the overload as a free function



      auto operator + (C lhs, const C& rhs)
      {
      lhs += rhs;
      return lhs;
      }


      Now, there is no restriction of the left hand side operand. Note that the operator is implemented in terms of += (you would have to implement it to make the above code compile), which is good practice as pointed out in this thread: when you provide a binary operator + for a custom type, users of that type will also expected operator += to be available. Hence, to reduce code duplication, it's usually good to implement + in terms of += (same for all other arithmetic operands).



      Further note that these operands often require a substantial amount of boilerplate code. To reduce this, consider e.g. the Boost operators library. To generate all standard arithmetic operators based on the minimal amount of actual hand-written code:



      #include <boost/operators.hpp>

      class C : private boost::arithmetic<C>
      // ^^^^^^^^^^^^^^^^^^^^
      // where the magic happens (Barton-Nackmann trick)
      {
      int m_value ;

      public:
      C(int value): m_value(value) {} ;

      C& operator+=(const C& rhs) { m_value += rhs.m_value; return *this; }
      C& operator-=(const C& rhs) { m_value -= rhs.m_value; return *this; }
      C& operator*=(const C& rhs) { m_value *= rhs.m_value; return *this; }
      C& operator/=(const C& rhs) { m_value /= rhs.m_value; return *this; }
      const C& operator+() const { return *this; }
      C operator-() const { return {-m_value}; }

      int get_value() { return m_value; } ;
      };





      share|improve this answer


























      • Just a matter of taste: While auto operator + (C lhs, const C& rhs) is fine for brevity, I personally prefer having two references and creating the copy explicitly internally for the sake of symmetry of the function signature - especially if implementation is hidden in a cpp file...

        – Aconcagua
        Feb 13 at 10:15






      • 3





        @Aconcagua Though you might end up with an unnecessary copy if you invoke the operator with a temporary left hand side, right?

        – lubgr
        Feb 13 at 10:21













      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54666628%2fwhat-type-does-the-conversion-logic-target%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      3














      Here's an additional remark (a bit of a "reductio ad absurdum") on why your suggestion that the compiler could implicitly convert the left hand argument to a C would, essentially, open a can of worms. The actual language rules say, simply put, that, before applying conversions, a name lookup – for function calls and calls to (user-declared) operators – is done to find a candidate set. At this point, the operand types are not yet considered, but the scope very well is. So the type of the first argument does matter insofar as a user-declared operator is only in scope if its first argument is of the (cv-qualified) class type it is declared in. When a candidate set has been found, the compiler then tries to apply the conversion rules and ranks the candidates etc.



      (Your question is therefore a bit misleading because in your example, we don't even get to the conversion logic, instead name resolution already comes up empty.)



      Now, imagine we could simply change the language to say that the first argument can also be converted, prior to name resolution. A little bit of handwaving is required here, because this means we have to do conversions, look up names, and then do conversions again, so how this would work in practice is certainly unclear. Anyway, look at this example then:



      struct B;
      struct A
      {
      A(int);
      A operator +(B) const;
      };
      struct B
      {
      B(int);
      B operator +(B) const;
      };


      Now, what should 1 + B{3} do? Apparently, it could be transformed to B{1} + B{3}. But who's to say we couldn't do A{1} + B{3} instead? Why would B's constructor be preferred over A's? Of course, we could argue that either B is to be preferred, because, look at how nice and symmetric B{...}+B{...} is (ok, I'm being slightly facetious). Or we could take the safer route of saying that the program is ill-formed if it contains such an ambiguity. But there are a lot more corner cases to consider, e.g. what if B's constructor was made explicit – should the compiler (still or newly) error out, or should it silently switch to the usable implicit conversion to A?



      Another non-obvious point is which types in which scopes (e.g. namespaces) should be considered? It would certainly be surprising if you use operator + in e.g. global namespace scope, and the compiler would dig out some type __gnucxx::__internal::__cogwheels::__do_something_impl, implcitly convert an operand to it, and then perform an operation on that.



      Also note that this feature even if it can be specified in a reasonable and clean manner, could have quite a compile-time cost (in fact, overload resolution is already one of the biggests costs when compiling C++ and one of the reasons why compiling C++ code can take a lot longer than compiling C).



      TL;DR:




      • There are tricky corner cases.

      • The benefit is marginal (why not make such operators free functions as others have pointed out)?

      • The discussions on how to standardize this would certainly be long.






      share|improve this answer




























        3














        Here's an additional remark (a bit of a "reductio ad absurdum") on why your suggestion that the compiler could implicitly convert the left hand argument to a C would, essentially, open a can of worms. The actual language rules say, simply put, that, before applying conversions, a name lookup – for function calls and calls to (user-declared) operators – is done to find a candidate set. At this point, the operand types are not yet considered, but the scope very well is. So the type of the first argument does matter insofar as a user-declared operator is only in scope if its first argument is of the (cv-qualified) class type it is declared in. When a candidate set has been found, the compiler then tries to apply the conversion rules and ranks the candidates etc.



        (Your question is therefore a bit misleading because in your example, we don't even get to the conversion logic, instead name resolution already comes up empty.)



        Now, imagine we could simply change the language to say that the first argument can also be converted, prior to name resolution. A little bit of handwaving is required here, because this means we have to do conversions, look up names, and then do conversions again, so how this would work in practice is certainly unclear. Anyway, look at this example then:



        struct B;
        struct A
        {
        A(int);
        A operator +(B) const;
        };
        struct B
        {
        B(int);
        B operator +(B) const;
        };


        Now, what should 1 + B{3} do? Apparently, it could be transformed to B{1} + B{3}. But who's to say we couldn't do A{1} + B{3} instead? Why would B's constructor be preferred over A's? Of course, we could argue that either B is to be preferred, because, look at how nice and symmetric B{...}+B{...} is (ok, I'm being slightly facetious). Or we could take the safer route of saying that the program is ill-formed if it contains such an ambiguity. But there are a lot more corner cases to consider, e.g. what if B's constructor was made explicit – should the compiler (still or newly) error out, or should it silently switch to the usable implicit conversion to A?



        Another non-obvious point is which types in which scopes (e.g. namespaces) should be considered? It would certainly be surprising if you use operator + in e.g. global namespace scope, and the compiler would dig out some type __gnucxx::__internal::__cogwheels::__do_something_impl, implcitly convert an operand to it, and then perform an operation on that.



        Also note that this feature even if it can be specified in a reasonable and clean manner, could have quite a compile-time cost (in fact, overload resolution is already one of the biggests costs when compiling C++ and one of the reasons why compiling C++ code can take a lot longer than compiling C).



        TL;DR:




        • There are tricky corner cases.

        • The benefit is marginal (why not make such operators free functions as others have pointed out)?

        • The discussions on how to standardize this would certainly be long.






        share|improve this answer


























          3












          3








          3







          Here's an additional remark (a bit of a "reductio ad absurdum") on why your suggestion that the compiler could implicitly convert the left hand argument to a C would, essentially, open a can of worms. The actual language rules say, simply put, that, before applying conversions, a name lookup – for function calls and calls to (user-declared) operators – is done to find a candidate set. At this point, the operand types are not yet considered, but the scope very well is. So the type of the first argument does matter insofar as a user-declared operator is only in scope if its first argument is of the (cv-qualified) class type it is declared in. When a candidate set has been found, the compiler then tries to apply the conversion rules and ranks the candidates etc.



          (Your question is therefore a bit misleading because in your example, we don't even get to the conversion logic, instead name resolution already comes up empty.)



          Now, imagine we could simply change the language to say that the first argument can also be converted, prior to name resolution. A little bit of handwaving is required here, because this means we have to do conversions, look up names, and then do conversions again, so how this would work in practice is certainly unclear. Anyway, look at this example then:



          struct B;
          struct A
          {
          A(int);
          A operator +(B) const;
          };
          struct B
          {
          B(int);
          B operator +(B) const;
          };


          Now, what should 1 + B{3} do? Apparently, it could be transformed to B{1} + B{3}. But who's to say we couldn't do A{1} + B{3} instead? Why would B's constructor be preferred over A's? Of course, we could argue that either B is to be preferred, because, look at how nice and symmetric B{...}+B{...} is (ok, I'm being slightly facetious). Or we could take the safer route of saying that the program is ill-formed if it contains such an ambiguity. But there are a lot more corner cases to consider, e.g. what if B's constructor was made explicit – should the compiler (still or newly) error out, or should it silently switch to the usable implicit conversion to A?



          Another non-obvious point is which types in which scopes (e.g. namespaces) should be considered? It would certainly be surprising if you use operator + in e.g. global namespace scope, and the compiler would dig out some type __gnucxx::__internal::__cogwheels::__do_something_impl, implcitly convert an operand to it, and then perform an operation on that.



          Also note that this feature even if it can be specified in a reasonable and clean manner, could have quite a compile-time cost (in fact, overload resolution is already one of the biggests costs when compiling C++ and one of the reasons why compiling C++ code can take a lot longer than compiling C).



          TL;DR:




          • There are tricky corner cases.

          • The benefit is marginal (why not make such operators free functions as others have pointed out)?

          • The discussions on how to standardize this would certainly be long.






          share|improve this answer













          Here's an additional remark (a bit of a "reductio ad absurdum") on why your suggestion that the compiler could implicitly convert the left hand argument to a C would, essentially, open a can of worms. The actual language rules say, simply put, that, before applying conversions, a name lookup – for function calls and calls to (user-declared) operators – is done to find a candidate set. At this point, the operand types are not yet considered, but the scope very well is. So the type of the first argument does matter insofar as a user-declared operator is only in scope if its first argument is of the (cv-qualified) class type it is declared in. When a candidate set has been found, the compiler then tries to apply the conversion rules and ranks the candidates etc.



          (Your question is therefore a bit misleading because in your example, we don't even get to the conversion logic, instead name resolution already comes up empty.)



          Now, imagine we could simply change the language to say that the first argument can also be converted, prior to name resolution. A little bit of handwaving is required here, because this means we have to do conversions, look up names, and then do conversions again, so how this would work in practice is certainly unclear. Anyway, look at this example then:



          struct B;
          struct A
          {
          A(int);
          A operator +(B) const;
          };
          struct B
          {
          B(int);
          B operator +(B) const;
          };


          Now, what should 1 + B{3} do? Apparently, it could be transformed to B{1} + B{3}. But who's to say we couldn't do A{1} + B{3} instead? Why would B's constructor be preferred over A's? Of course, we could argue that either B is to be preferred, because, look at how nice and symmetric B{...}+B{...} is (ok, I'm being slightly facetious). Or we could take the safer route of saying that the program is ill-formed if it contains such an ambiguity. But there are a lot more corner cases to consider, e.g. what if B's constructor was made explicit – should the compiler (still or newly) error out, or should it silently switch to the usable implicit conversion to A?



          Another non-obvious point is which types in which scopes (e.g. namespaces) should be considered? It would certainly be surprising if you use operator + in e.g. global namespace scope, and the compiler would dig out some type __gnucxx::__internal::__cogwheels::__do_something_impl, implcitly convert an operand to it, and then perform an operation on that.



          Also note that this feature even if it can be specified in a reasonable and clean manner, could have quite a compile-time cost (in fact, overload resolution is already one of the biggests costs when compiling C++ and one of the reasons why compiling C++ code can take a lot longer than compiling C).



          TL;DR:




          • There are tricky corner cases.

          • The benefit is marginal (why not make such operators free functions as others have pointed out)?

          • The discussions on how to standardize this would certainly be long.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Feb 13 at 10:50









          Arne VogelArne Vogel

          4,87521326




          4,87521326

























              21














              Because if overload operator as member function of the class, it could only be called when the object of that class is used as left operand. (And the left operand becomes the implicit *this object for the member function to be called.)




              Binary operators are typically implemented as non-members to maintain symmetry (for example, when adding a complex number and an integer, if operator+ is a member function of the complex type, then only complex+integer would compile, and not integer+complex).




              From the standard, [over.match.oper]/3



              (emphasis mine)




              For a unary operator @ with an operand of a type whose cv-unqualified
              version is T1, and for a binary operator @ with a left operand of a
              type whose cv-unqualified version is T1 and a right operand of a type
              whose cv-unqualified version is T2, four sets of candidate functions,
              designated member candidates, non-member candidates, built-in
              candidates, and rewritten candidates, are constructed as follows:




              • (3.1) If T1 is a complete class type or a class currently being defined, the set of member candidates is the result of the qualified
                lookup of T1::operator@ ([over.call.func]); otherwise, the set of
                member candidates is empty
                .




              That means if the type of left operand is not a class type, the set of member candidates is empty; the overloaded operator (as member function) won't be considered.



              You can overload it as a non-member function to allow the implicit conversion for both left and right operands.



              C operator+(C lhs, C rhs) { return C(lhs.get_value() + rhs.get_value()); }


              then both c + 5 or 5 + c would work fine.



              LIVE



              BTW: This will cause one temporaray object being constructed (from int to C) for the non-member function to be called; if you care about that, you can add all the three possible overloads as follows. Also note that this is a trade-off issue.



              C operator+(C lhs, C rhs) { return C(lhs.get_value() + rhs.get_value()); }
              C operator+(C lhs, int rhs) { return C(lhs.get_value() + rhs); }
              C operator+(int lhs, C rhs) { return C(lhs + rhs.get_value()); }


              And here're some suggestions about when to use a normal, friend, or member function overload.




              In most cases, the language leaves it up to you to determine whether
              you want to use the normal/friend or member function version of the
              overload. However, one of the two is usually a better choice than the
              other.



              When dealing with binary operators that don’t modify the left operand
              (e.g. operator+), the normal or friend function version is typically
              preferred, because it works for all parameter types (even when the
              left operand isn’t a class object, or is a class that is not
              modifiable). The normal or friend function version has the added
              benefit of “symmetry”, as all operands become explicit parameters
              (instead of the left operand becoming *this and the right operand
              becoming an explicit parameter).



              When dealing with binary operators that do modify the left operand
              (e.g. operator+=), the member function version is typically preferred.
              In these cases, the leftmost operand will always be a class type, and
              having the object being modified become the one pointed to by *this is
              natural. Because the rightmost operand becomes an explicit parameter,
              there’s no confusion over who is getting modified and who is getting
              evaluated.







              share|improve this answer






























                21














                Because if overload operator as member function of the class, it could only be called when the object of that class is used as left operand. (And the left operand becomes the implicit *this object for the member function to be called.)




                Binary operators are typically implemented as non-members to maintain symmetry (for example, when adding a complex number and an integer, if operator+ is a member function of the complex type, then only complex+integer would compile, and not integer+complex).




                From the standard, [over.match.oper]/3



                (emphasis mine)




                For a unary operator @ with an operand of a type whose cv-unqualified
                version is T1, and for a binary operator @ with a left operand of a
                type whose cv-unqualified version is T1 and a right operand of a type
                whose cv-unqualified version is T2, four sets of candidate functions,
                designated member candidates, non-member candidates, built-in
                candidates, and rewritten candidates, are constructed as follows:




                • (3.1) If T1 is a complete class type or a class currently being defined, the set of member candidates is the result of the qualified
                  lookup of T1::operator@ ([over.call.func]); otherwise, the set of
                  member candidates is empty
                  .




                That means if the type of left operand is not a class type, the set of member candidates is empty; the overloaded operator (as member function) won't be considered.



                You can overload it as a non-member function to allow the implicit conversion for both left and right operands.



                C operator+(C lhs, C rhs) { return C(lhs.get_value() + rhs.get_value()); }


                then both c + 5 or 5 + c would work fine.



                LIVE



                BTW: This will cause one temporaray object being constructed (from int to C) for the non-member function to be called; if you care about that, you can add all the three possible overloads as follows. Also note that this is a trade-off issue.



                C operator+(C lhs, C rhs) { return C(lhs.get_value() + rhs.get_value()); }
                C operator+(C lhs, int rhs) { return C(lhs.get_value() + rhs); }
                C operator+(int lhs, C rhs) { return C(lhs + rhs.get_value()); }


                And here're some suggestions about when to use a normal, friend, or member function overload.




                In most cases, the language leaves it up to you to determine whether
                you want to use the normal/friend or member function version of the
                overload. However, one of the two is usually a better choice than the
                other.



                When dealing with binary operators that don’t modify the left operand
                (e.g. operator+), the normal or friend function version is typically
                preferred, because it works for all parameter types (even when the
                left operand isn’t a class object, or is a class that is not
                modifiable). The normal or friend function version has the added
                benefit of “symmetry”, as all operands become explicit parameters
                (instead of the left operand becoming *this and the right operand
                becoming an explicit parameter).



                When dealing with binary operators that do modify the left operand
                (e.g. operator+=), the member function version is typically preferred.
                In these cases, the leftmost operand will always be a class type, and
                having the object being modified become the one pointed to by *this is
                natural. Because the rightmost operand becomes an explicit parameter,
                there’s no confusion over who is getting modified and who is getting
                evaluated.







                share|improve this answer




























                  21












                  21








                  21







                  Because if overload operator as member function of the class, it could only be called when the object of that class is used as left operand. (And the left operand becomes the implicit *this object for the member function to be called.)




                  Binary operators are typically implemented as non-members to maintain symmetry (for example, when adding a complex number and an integer, if operator+ is a member function of the complex type, then only complex+integer would compile, and not integer+complex).




                  From the standard, [over.match.oper]/3



                  (emphasis mine)




                  For a unary operator @ with an operand of a type whose cv-unqualified
                  version is T1, and for a binary operator @ with a left operand of a
                  type whose cv-unqualified version is T1 and a right operand of a type
                  whose cv-unqualified version is T2, four sets of candidate functions,
                  designated member candidates, non-member candidates, built-in
                  candidates, and rewritten candidates, are constructed as follows:




                  • (3.1) If T1 is a complete class type or a class currently being defined, the set of member candidates is the result of the qualified
                    lookup of T1::operator@ ([over.call.func]); otherwise, the set of
                    member candidates is empty
                    .




                  That means if the type of left operand is not a class type, the set of member candidates is empty; the overloaded operator (as member function) won't be considered.



                  You can overload it as a non-member function to allow the implicit conversion for both left and right operands.



                  C operator+(C lhs, C rhs) { return C(lhs.get_value() + rhs.get_value()); }


                  then both c + 5 or 5 + c would work fine.



                  LIVE



                  BTW: This will cause one temporaray object being constructed (from int to C) for the non-member function to be called; if you care about that, you can add all the three possible overloads as follows. Also note that this is a trade-off issue.



                  C operator+(C lhs, C rhs) { return C(lhs.get_value() + rhs.get_value()); }
                  C operator+(C lhs, int rhs) { return C(lhs.get_value() + rhs); }
                  C operator+(int lhs, C rhs) { return C(lhs + rhs.get_value()); }


                  And here're some suggestions about when to use a normal, friend, or member function overload.




                  In most cases, the language leaves it up to you to determine whether
                  you want to use the normal/friend or member function version of the
                  overload. However, one of the two is usually a better choice than the
                  other.



                  When dealing with binary operators that don’t modify the left operand
                  (e.g. operator+), the normal or friend function version is typically
                  preferred, because it works for all parameter types (even when the
                  left operand isn’t a class object, or is a class that is not
                  modifiable). The normal or friend function version has the added
                  benefit of “symmetry”, as all operands become explicit parameters
                  (instead of the left operand becoming *this and the right operand
                  becoming an explicit parameter).



                  When dealing with binary operators that do modify the left operand
                  (e.g. operator+=), the member function version is typically preferred.
                  In these cases, the leftmost operand will always be a class type, and
                  having the object being modified become the one pointed to by *this is
                  natural. Because the rightmost operand becomes an explicit parameter,
                  there’s no confusion over who is getting modified and who is getting
                  evaluated.







                  share|improve this answer















                  Because if overload operator as member function of the class, it could only be called when the object of that class is used as left operand. (And the left operand becomes the implicit *this object for the member function to be called.)




                  Binary operators are typically implemented as non-members to maintain symmetry (for example, when adding a complex number and an integer, if operator+ is a member function of the complex type, then only complex+integer would compile, and not integer+complex).




                  From the standard, [over.match.oper]/3



                  (emphasis mine)




                  For a unary operator @ with an operand of a type whose cv-unqualified
                  version is T1, and for a binary operator @ with a left operand of a
                  type whose cv-unqualified version is T1 and a right operand of a type
                  whose cv-unqualified version is T2, four sets of candidate functions,
                  designated member candidates, non-member candidates, built-in
                  candidates, and rewritten candidates, are constructed as follows:




                  • (3.1) If T1 is a complete class type or a class currently being defined, the set of member candidates is the result of the qualified
                    lookup of T1::operator@ ([over.call.func]); otherwise, the set of
                    member candidates is empty
                    .




                  That means if the type of left operand is not a class type, the set of member candidates is empty; the overloaded operator (as member function) won't be considered.



                  You can overload it as a non-member function to allow the implicit conversion for both left and right operands.



                  C operator+(C lhs, C rhs) { return C(lhs.get_value() + rhs.get_value()); }


                  then both c + 5 or 5 + c would work fine.



                  LIVE



                  BTW: This will cause one temporaray object being constructed (from int to C) for the non-member function to be called; if you care about that, you can add all the three possible overloads as follows. Also note that this is a trade-off issue.



                  C operator+(C lhs, C rhs) { return C(lhs.get_value() + rhs.get_value()); }
                  C operator+(C lhs, int rhs) { return C(lhs.get_value() + rhs); }
                  C operator+(int lhs, C rhs) { return C(lhs + rhs.get_value()); }


                  And here're some suggestions about when to use a normal, friend, or member function overload.




                  In most cases, the language leaves it up to you to determine whether
                  you want to use the normal/friend or member function version of the
                  overload. However, one of the two is usually a better choice than the
                  other.



                  When dealing with binary operators that don’t modify the left operand
                  (e.g. operator+), the normal or friend function version is typically
                  preferred, because it works for all parameter types (even when the
                  left operand isn’t a class object, or is a class that is not
                  modifiable). The normal or friend function version has the added
                  benefit of “symmetry”, as all operands become explicit parameters
                  (instead of the left operand becoming *this and the right operand
                  becoming an explicit parameter).



                  When dealing with binary operators that do modify the left operand
                  (e.g. operator+=), the member function version is typically preferred.
                  In these cases, the leftmost operand will always be a class type, and
                  having the object being modified become the one pointed to by *this is
                  natural. Because the rightmost operand becomes an explicit parameter,
                  there’s no confusion over who is getting modified and who is getting
                  evaluated.








                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Feb 13 at 10:42

























                  answered Feb 13 at 9:29









                  songyuanyaosongyuanyao

                  92.9k11179246




                  92.9k11179246























                      8














                      You are facing the reason to define certain operator overloads as free functions, i.e., when implicit conversions are desired. To see what's going on under the hood, consider the verbose form of operator overload invocations:



                      C c2 = c.operator+(5); // Ok, c has this member function
                      C c3 = 5.operator+(c); // No way, this is an integer without members


                      You can obviously do is an explicit C construction as in



                      C c3 = C{5} + c;


                      but this is not intended for an arithmetic value type like C. To make the implicit construction possible, define the overload as a free function



                      auto operator + (C lhs, const C& rhs)
                      {
                      lhs += rhs;
                      return lhs;
                      }


                      Now, there is no restriction of the left hand side operand. Note that the operator is implemented in terms of += (you would have to implement it to make the above code compile), which is good practice as pointed out in this thread: when you provide a binary operator + for a custom type, users of that type will also expected operator += to be available. Hence, to reduce code duplication, it's usually good to implement + in terms of += (same for all other arithmetic operands).



                      Further note that these operands often require a substantial amount of boilerplate code. To reduce this, consider e.g. the Boost operators library. To generate all standard arithmetic operators based on the minimal amount of actual hand-written code:



                      #include <boost/operators.hpp>

                      class C : private boost::arithmetic<C>
                      // ^^^^^^^^^^^^^^^^^^^^
                      // where the magic happens (Barton-Nackmann trick)
                      {
                      int m_value ;

                      public:
                      C(int value): m_value(value) {} ;

                      C& operator+=(const C& rhs) { m_value += rhs.m_value; return *this; }
                      C& operator-=(const C& rhs) { m_value -= rhs.m_value; return *this; }
                      C& operator*=(const C& rhs) { m_value *= rhs.m_value; return *this; }
                      C& operator/=(const C& rhs) { m_value /= rhs.m_value; return *this; }
                      const C& operator+() const { return *this; }
                      C operator-() const { return {-m_value}; }

                      int get_value() { return m_value; } ;
                      };





                      share|improve this answer


























                      • Just a matter of taste: While auto operator + (C lhs, const C& rhs) is fine for brevity, I personally prefer having two references and creating the copy explicitly internally for the sake of symmetry of the function signature - especially if implementation is hidden in a cpp file...

                        – Aconcagua
                        Feb 13 at 10:15






                      • 3





                        @Aconcagua Though you might end up with an unnecessary copy if you invoke the operator with a temporary left hand side, right?

                        – lubgr
                        Feb 13 at 10:21


















                      8














                      You are facing the reason to define certain operator overloads as free functions, i.e., when implicit conversions are desired. To see what's going on under the hood, consider the verbose form of operator overload invocations:



                      C c2 = c.operator+(5); // Ok, c has this member function
                      C c3 = 5.operator+(c); // No way, this is an integer without members


                      You can obviously do is an explicit C construction as in



                      C c3 = C{5} + c;


                      but this is not intended for an arithmetic value type like C. To make the implicit construction possible, define the overload as a free function



                      auto operator + (C lhs, const C& rhs)
                      {
                      lhs += rhs;
                      return lhs;
                      }


                      Now, there is no restriction of the left hand side operand. Note that the operator is implemented in terms of += (you would have to implement it to make the above code compile), which is good practice as pointed out in this thread: when you provide a binary operator + for a custom type, users of that type will also expected operator += to be available. Hence, to reduce code duplication, it's usually good to implement + in terms of += (same for all other arithmetic operands).



                      Further note that these operands often require a substantial amount of boilerplate code. To reduce this, consider e.g. the Boost operators library. To generate all standard arithmetic operators based on the minimal amount of actual hand-written code:



                      #include <boost/operators.hpp>

                      class C : private boost::arithmetic<C>
                      // ^^^^^^^^^^^^^^^^^^^^
                      // where the magic happens (Barton-Nackmann trick)
                      {
                      int m_value ;

                      public:
                      C(int value): m_value(value) {} ;

                      C& operator+=(const C& rhs) { m_value += rhs.m_value; return *this; }
                      C& operator-=(const C& rhs) { m_value -= rhs.m_value; return *this; }
                      C& operator*=(const C& rhs) { m_value *= rhs.m_value; return *this; }
                      C& operator/=(const C& rhs) { m_value /= rhs.m_value; return *this; }
                      const C& operator+() const { return *this; }
                      C operator-() const { return {-m_value}; }

                      int get_value() { return m_value; } ;
                      };





                      share|improve this answer


























                      • Just a matter of taste: While auto operator + (C lhs, const C& rhs) is fine for brevity, I personally prefer having two references and creating the copy explicitly internally for the sake of symmetry of the function signature - especially if implementation is hidden in a cpp file...

                        – Aconcagua
                        Feb 13 at 10:15






                      • 3





                        @Aconcagua Though you might end up with an unnecessary copy if you invoke the operator with a temporary left hand side, right?

                        – lubgr
                        Feb 13 at 10:21
















                      8












                      8








                      8







                      You are facing the reason to define certain operator overloads as free functions, i.e., when implicit conversions are desired. To see what's going on under the hood, consider the verbose form of operator overload invocations:



                      C c2 = c.operator+(5); // Ok, c has this member function
                      C c3 = 5.operator+(c); // No way, this is an integer without members


                      You can obviously do is an explicit C construction as in



                      C c3 = C{5} + c;


                      but this is not intended for an arithmetic value type like C. To make the implicit construction possible, define the overload as a free function



                      auto operator + (C lhs, const C& rhs)
                      {
                      lhs += rhs;
                      return lhs;
                      }


                      Now, there is no restriction of the left hand side operand. Note that the operator is implemented in terms of += (you would have to implement it to make the above code compile), which is good practice as pointed out in this thread: when you provide a binary operator + for a custom type, users of that type will also expected operator += to be available. Hence, to reduce code duplication, it's usually good to implement + in terms of += (same for all other arithmetic operands).



                      Further note that these operands often require a substantial amount of boilerplate code. To reduce this, consider e.g. the Boost operators library. To generate all standard arithmetic operators based on the minimal amount of actual hand-written code:



                      #include <boost/operators.hpp>

                      class C : private boost::arithmetic<C>
                      // ^^^^^^^^^^^^^^^^^^^^
                      // where the magic happens (Barton-Nackmann trick)
                      {
                      int m_value ;

                      public:
                      C(int value): m_value(value) {} ;

                      C& operator+=(const C& rhs) { m_value += rhs.m_value; return *this; }
                      C& operator-=(const C& rhs) { m_value -= rhs.m_value; return *this; }
                      C& operator*=(const C& rhs) { m_value *= rhs.m_value; return *this; }
                      C& operator/=(const C& rhs) { m_value /= rhs.m_value; return *this; }
                      const C& operator+() const { return *this; }
                      C operator-() const { return {-m_value}; }

                      int get_value() { return m_value; } ;
                      };





                      share|improve this answer















                      You are facing the reason to define certain operator overloads as free functions, i.e., when implicit conversions are desired. To see what's going on under the hood, consider the verbose form of operator overload invocations:



                      C c2 = c.operator+(5); // Ok, c has this member function
                      C c3 = 5.operator+(c); // No way, this is an integer without members


                      You can obviously do is an explicit C construction as in



                      C c3 = C{5} + c;


                      but this is not intended for an arithmetic value type like C. To make the implicit construction possible, define the overload as a free function



                      auto operator + (C lhs, const C& rhs)
                      {
                      lhs += rhs;
                      return lhs;
                      }


                      Now, there is no restriction of the left hand side operand. Note that the operator is implemented in terms of += (you would have to implement it to make the above code compile), which is good practice as pointed out in this thread: when you provide a binary operator + for a custom type, users of that type will also expected operator += to be available. Hence, to reduce code duplication, it's usually good to implement + in terms of += (same for all other arithmetic operands).



                      Further note that these operands often require a substantial amount of boilerplate code. To reduce this, consider e.g. the Boost operators library. To generate all standard arithmetic operators based on the minimal amount of actual hand-written code:



                      #include <boost/operators.hpp>

                      class C : private boost::arithmetic<C>
                      // ^^^^^^^^^^^^^^^^^^^^
                      // where the magic happens (Barton-Nackmann trick)
                      {
                      int m_value ;

                      public:
                      C(int value): m_value(value) {} ;

                      C& operator+=(const C& rhs) { m_value += rhs.m_value; return *this; }
                      C& operator-=(const C& rhs) { m_value -= rhs.m_value; return *this; }
                      C& operator*=(const C& rhs) { m_value *= rhs.m_value; return *this; }
                      C& operator/=(const C& rhs) { m_value /= rhs.m_value; return *this; }
                      const C& operator+() const { return *this; }
                      C operator-() const { return {-m_value}; }

                      int get_value() { return m_value; } ;
                      };






                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Feb 13 at 9:51

























                      answered Feb 13 at 9:32









                      lubgrlubgr

                      13.5k31850




                      13.5k31850













                      • Just a matter of taste: While auto operator + (C lhs, const C& rhs) is fine for brevity, I personally prefer having two references and creating the copy explicitly internally for the sake of symmetry of the function signature - especially if implementation is hidden in a cpp file...

                        – Aconcagua
                        Feb 13 at 10:15






                      • 3





                        @Aconcagua Though you might end up with an unnecessary copy if you invoke the operator with a temporary left hand side, right?

                        – lubgr
                        Feb 13 at 10:21





















                      • Just a matter of taste: While auto operator + (C lhs, const C& rhs) is fine for brevity, I personally prefer having two references and creating the copy explicitly internally for the sake of symmetry of the function signature - especially if implementation is hidden in a cpp file...

                        – Aconcagua
                        Feb 13 at 10:15






                      • 3





                        @Aconcagua Though you might end up with an unnecessary copy if you invoke the operator with a temporary left hand side, right?

                        – lubgr
                        Feb 13 at 10:21



















                      Just a matter of taste: While auto operator + (C lhs, const C& rhs) is fine for brevity, I personally prefer having two references and creating the copy explicitly internally for the sake of symmetry of the function signature - especially if implementation is hidden in a cpp file...

                      – Aconcagua
                      Feb 13 at 10:15





                      Just a matter of taste: While auto operator + (C lhs, const C& rhs) is fine for brevity, I personally prefer having two references and creating the copy explicitly internally for the sake of symmetry of the function signature - especially if implementation is hidden in a cpp file...

                      – Aconcagua
                      Feb 13 at 10:15




                      3




                      3





                      @Aconcagua Though you might end up with an unnecessary copy if you invoke the operator with a temporary left hand side, right?

                      – lubgr
                      Feb 13 at 10:21







                      @Aconcagua Though you might end up with an unnecessary copy if you invoke the operator with a temporary left hand side, right?

                      – lubgr
                      Feb 13 at 10:21




















                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54666628%2fwhat-type-does-the-conversion-logic-target%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Probability when a professor distributes a quiz and homework assignment to a class of n students.

                      Aardman Animations

                      Are they similar matrix