Why is implicit conversion not ambiguous for non-primitive types?Can you use keyword explicit to prevent automatic conversion of method parameters?Why const for implicit conversion?Implicit conversion when overloading operators for template classesTemplate Constructor for Primitives, avoiding AmbiguityTemplate Type Deduction with Lambdasimplicit conversions from and to class typesConversion is ambiguous. Standard implicit conversion could not choose cast operatorGet type of implicit conversionImplicit conversion of stream to boolC++17: explicit conversion function vs explicit constructor + implicit conversions - have the rules changed?

Is there any common country to visit for persons holding UK and Schengen visas?

Travelling in US for more than 90 days

Why didn't Voldemort know what Grindelwald looked like?

Friend wants my recommendation but I don't want to give it to him

Capacitor electron flow

How to preserve electronics (computers, ipads, phones) for hundreds of years?

Extract substring according to regexp with sed or grep

Should a narrator ever describe things based on a character's view instead of facts?

Trouble reading roman numeral notation with flats

Why didn’t Eve recognize the little cockroach as a living organism?

What (if any) is the reason to buy in small local stores?

categorizing a variable turns it from insignificant to significant

What is the meaning of "You've never met a graph you didn't like?"

How do you say "Trust your struggle." in French?

Reason why a kingside attack is not justified

How do you justify more code being written by following clean code practices?

Is divisi notation needed for brass or woodwind in an orchestra?

Reasons for having MCU pin-states default to pull-up/down out of reset

is this saw blade faulty?

Why is participating in the European Parliamentary elections used as a threat?

What properties make a magic weapon befit a Rogue more than a DEX-based Fighter?

Comic-book: Kids find a dead female superhero in the woods

What 1968 Moog synthesizer was used in the Movie Apollo 11?

What's the meaning of "what it means for something to be something"?



Why is implicit conversion not ambiguous for non-primitive types?


Can you use keyword explicit to prevent automatic conversion of method parameters?Why const for implicit conversion?Implicit conversion when overloading operators for template classesTemplate Constructor for Primitives, avoiding AmbiguityTemplate Type Deduction with Lambdasimplicit conversions from and to class typesConversion is ambiguous. Standard implicit conversion could not choose cast operatorGet type of implicit conversionImplicit conversion of stream to boolC++17: explicit conversion function vs explicit constructor + implicit conversions - have the rules changed?













8















Given a simple class template with multiple implicit conversion functions (non-explicit constructor and conversion operator), as in the following example:



template<class T>
class Foo

private:
T m_value;

public:
Foo();

Foo(const T& value):
m_value(value)



operator T() const
return m_value;


bool operator==(const Foo<T>& other) const
return m_value == other.m_value;

;

struct Bar

bool m;

bool operator==(const Bar& other) const
return false;

;

int main(int argc, char *argv[])

Foo<bool> a (true);
bool b = false;
if(a == b)
// This is ambiguous


Foo<int> c (1);
int d = 2;
if(c == d)
// This is ambiguous


Foo<Bar> e (Bartrue);
Bar f = false;
if(e == f)
// This is not ambiguous. Why?




The comparison operators involving primitive types (bool, int) are ambiguous, as expected - the compiler does not know whether it should use the conversion operator to convert the left-hand template class instance to a primitive type or use the conversion constructor to convert the right-hand primitive type to the expected class template instance.



However, the last comparison, involving a simple struct, is not ambiguous. Why? Which conversion function will be used?



Tested with compiler msvc 15.9.7.










share|improve this question

















  • 1





    The explicit keyword is a nice thing. You should research it.

    – Jesper Juhl
    3 hours ago











  • e == f will be ambiguous in C++20, for what its worth.

    – Barry
    3 hours ago















8















Given a simple class template with multiple implicit conversion functions (non-explicit constructor and conversion operator), as in the following example:



template<class T>
class Foo

private:
T m_value;

public:
Foo();

Foo(const T& value):
m_value(value)



operator T() const
return m_value;


bool operator==(const Foo<T>& other) const
return m_value == other.m_value;

;

struct Bar

bool m;

bool operator==(const Bar& other) const
return false;

;

int main(int argc, char *argv[])

Foo<bool> a (true);
bool b = false;
if(a == b)
// This is ambiguous


Foo<int> c (1);
int d = 2;
if(c == d)
// This is ambiguous


Foo<Bar> e (Bartrue);
Bar f = false;
if(e == f)
// This is not ambiguous. Why?




The comparison operators involving primitive types (bool, int) are ambiguous, as expected - the compiler does not know whether it should use the conversion operator to convert the left-hand template class instance to a primitive type or use the conversion constructor to convert the right-hand primitive type to the expected class template instance.



However, the last comparison, involving a simple struct, is not ambiguous. Why? Which conversion function will be used?



Tested with compiler msvc 15.9.7.










share|improve this question

















  • 1





    The explicit keyword is a nice thing. You should research it.

    – Jesper Juhl
    3 hours ago











  • e == f will be ambiguous in C++20, for what its worth.

    – Barry
    3 hours ago













8












8








8








Given a simple class template with multiple implicit conversion functions (non-explicit constructor and conversion operator), as in the following example:



template<class T>
class Foo

private:
T m_value;

public:
Foo();

Foo(const T& value):
m_value(value)



operator T() const
return m_value;


bool operator==(const Foo<T>& other) const
return m_value == other.m_value;

;

struct Bar

bool m;

bool operator==(const Bar& other) const
return false;

;

int main(int argc, char *argv[])

Foo<bool> a (true);
bool b = false;
if(a == b)
// This is ambiguous


Foo<int> c (1);
int d = 2;
if(c == d)
// This is ambiguous


Foo<Bar> e (Bartrue);
Bar f = false;
if(e == f)
// This is not ambiguous. Why?




The comparison operators involving primitive types (bool, int) are ambiguous, as expected - the compiler does not know whether it should use the conversion operator to convert the left-hand template class instance to a primitive type or use the conversion constructor to convert the right-hand primitive type to the expected class template instance.



However, the last comparison, involving a simple struct, is not ambiguous. Why? Which conversion function will be used?



Tested with compiler msvc 15.9.7.










share|improve this question














Given a simple class template with multiple implicit conversion functions (non-explicit constructor and conversion operator), as in the following example:



template<class T>
class Foo

private:
T m_value;

public:
Foo();

Foo(const T& value):
m_value(value)



operator T() const
return m_value;


bool operator==(const Foo<T>& other) const
return m_value == other.m_value;

;

struct Bar

bool m;

bool operator==(const Bar& other) const
return false;

;

int main(int argc, char *argv[])

Foo<bool> a (true);
bool b = false;
if(a == b)
// This is ambiguous


Foo<int> c (1);
int d = 2;
if(c == d)
// This is ambiguous


Foo<Bar> e (Bartrue);
Bar f = false;
if(e == f)
// This is not ambiguous. Why?




The comparison operators involving primitive types (bool, int) are ambiguous, as expected - the compiler does not know whether it should use the conversion operator to convert the left-hand template class instance to a primitive type or use the conversion constructor to convert the right-hand primitive type to the expected class template instance.



However, the last comparison, involving a simple struct, is not ambiguous. Why? Which conversion function will be used?



Tested with compiler msvc 15.9.7.







c++ templates c++17 implicit-conversion ambiguous






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 3 hours ago









CybranCybran

1,052818




1,052818







  • 1





    The explicit keyword is a nice thing. You should research it.

    – Jesper Juhl
    3 hours ago











  • e == f will be ambiguous in C++20, for what its worth.

    – Barry
    3 hours ago












  • 1





    The explicit keyword is a nice thing. You should research it.

    – Jesper Juhl
    3 hours ago











  • e == f will be ambiguous in C++20, for what its worth.

    – Barry
    3 hours ago







1




1





The explicit keyword is a nice thing. You should research it.

– Jesper Juhl
3 hours ago





The explicit keyword is a nice thing. You should research it.

– Jesper Juhl
3 hours ago













e == f will be ambiguous in C++20, for what its worth.

– Barry
3 hours ago





e == f will be ambiguous in C++20, for what its worth.

– Barry
3 hours ago












2 Answers
2






active

oldest

votes


















11














According to [over.binary]/1




Thus, for any binary operator @, x@y can be interpreted
as either x.operator@(y) or operator@(x,y).




According to this rule, in the case of e == f, the compiler can only interpret it as e.operator==(f), not as f.operator==(e). So there is no ambiguity; the operator== you defined as a member of Bar is simply not a candidate for overload resolution.



In the case of a == b and c == d, the built-in candidate operator==(int, int) (see [over.built]/13) competes with the operator== defined as a member of Foo<T>.






share|improve this answer






























    3














    Operator overloads implemented as member functions don't allow for implicit conversion of their left-hand operand, which is the object on which they are called.



    It always helps to write out the explicit call of an operator overload to better understand exactly what it does:



    Foo<Bar> e (Bartrue);
    Bar f = false;

    // Pretty explicit: call the member function Foo<Bar>::operator==
    if(e.operator ==(f)) /* ... */


    This can't be confused with the comparison operator in Bar, because it would require an implicit conversion of the left-hand side, which is impossible.



    You can trigger an ambiguity similar to the ones you see with the built-in types when you define Bar and its comparison operator like this:



    struct Bar bool m; ;

    // A free function allows conversion, this will be ambiguous:
    bool operator==(const Bar&, const Bar&)

    return false;



    This is nicely demonstrated and explained in Scott Meyers's Effective C++, Item 24.






    share|improve this answer
























      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%2f55249017%2fwhy-is-implicit-conversion-not-ambiguous-for-non-primitive-types%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      11














      According to [over.binary]/1




      Thus, for any binary operator @, x@y can be interpreted
      as either x.operator@(y) or operator@(x,y).




      According to this rule, in the case of e == f, the compiler can only interpret it as e.operator==(f), not as f.operator==(e). So there is no ambiguity; the operator== you defined as a member of Bar is simply not a candidate for overload resolution.



      In the case of a == b and c == d, the built-in candidate operator==(int, int) (see [over.built]/13) competes with the operator== defined as a member of Foo<T>.






      share|improve this answer



























        11














        According to [over.binary]/1




        Thus, for any binary operator @, x@y can be interpreted
        as either x.operator@(y) or operator@(x,y).




        According to this rule, in the case of e == f, the compiler can only interpret it as e.operator==(f), not as f.operator==(e). So there is no ambiguity; the operator== you defined as a member of Bar is simply not a candidate for overload resolution.



        In the case of a == b and c == d, the built-in candidate operator==(int, int) (see [over.built]/13) competes with the operator== defined as a member of Foo<T>.






        share|improve this answer

























          11












          11








          11







          According to [over.binary]/1




          Thus, for any binary operator @, x@y can be interpreted
          as either x.operator@(y) or operator@(x,y).




          According to this rule, in the case of e == f, the compiler can only interpret it as e.operator==(f), not as f.operator==(e). So there is no ambiguity; the operator== you defined as a member of Bar is simply not a candidate for overload resolution.



          In the case of a == b and c == d, the built-in candidate operator==(int, int) (see [over.built]/13) competes with the operator== defined as a member of Foo<T>.






          share|improve this answer













          According to [over.binary]/1




          Thus, for any binary operator @, x@y can be interpreted
          as either x.operator@(y) or operator@(x,y).




          According to this rule, in the case of e == f, the compiler can only interpret it as e.operator==(f), not as f.operator==(e). So there is no ambiguity; the operator== you defined as a member of Bar is simply not a candidate for overload resolution.



          In the case of a == b and c == d, the built-in candidate operator==(int, int) (see [over.built]/13) competes with the operator== defined as a member of Foo<T>.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 3 hours ago









          BrianBrian

          65.6k797186




          65.6k797186























              3














              Operator overloads implemented as member functions don't allow for implicit conversion of their left-hand operand, which is the object on which they are called.



              It always helps to write out the explicit call of an operator overload to better understand exactly what it does:



              Foo<Bar> e (Bartrue);
              Bar f = false;

              // Pretty explicit: call the member function Foo<Bar>::operator==
              if(e.operator ==(f)) /* ... */


              This can't be confused with the comparison operator in Bar, because it would require an implicit conversion of the left-hand side, which is impossible.



              You can trigger an ambiguity similar to the ones you see with the built-in types when you define Bar and its comparison operator like this:



              struct Bar bool m; ;

              // A free function allows conversion, this will be ambiguous:
              bool operator==(const Bar&, const Bar&)

              return false;



              This is nicely demonstrated and explained in Scott Meyers's Effective C++, Item 24.






              share|improve this answer





























                3














                Operator overloads implemented as member functions don't allow for implicit conversion of their left-hand operand, which is the object on which they are called.



                It always helps to write out the explicit call of an operator overload to better understand exactly what it does:



                Foo<Bar> e (Bartrue);
                Bar f = false;

                // Pretty explicit: call the member function Foo<Bar>::operator==
                if(e.operator ==(f)) /* ... */


                This can't be confused with the comparison operator in Bar, because it would require an implicit conversion of the left-hand side, which is impossible.



                You can trigger an ambiguity similar to the ones you see with the built-in types when you define Bar and its comparison operator like this:



                struct Bar bool m; ;

                // A free function allows conversion, this will be ambiguous:
                bool operator==(const Bar&, const Bar&)

                return false;



                This is nicely demonstrated and explained in Scott Meyers's Effective C++, Item 24.






                share|improve this answer



























                  3












                  3








                  3







                  Operator overloads implemented as member functions don't allow for implicit conversion of their left-hand operand, which is the object on which they are called.



                  It always helps to write out the explicit call of an operator overload to better understand exactly what it does:



                  Foo<Bar> e (Bartrue);
                  Bar f = false;

                  // Pretty explicit: call the member function Foo<Bar>::operator==
                  if(e.operator ==(f)) /* ... */


                  This can't be confused with the comparison operator in Bar, because it would require an implicit conversion of the left-hand side, which is impossible.



                  You can trigger an ambiguity similar to the ones you see with the built-in types when you define Bar and its comparison operator like this:



                  struct Bar bool m; ;

                  // A free function allows conversion, this will be ambiguous:
                  bool operator==(const Bar&, const Bar&)

                  return false;



                  This is nicely demonstrated and explained in Scott Meyers's Effective C++, Item 24.






                  share|improve this answer















                  Operator overloads implemented as member functions don't allow for implicit conversion of their left-hand operand, which is the object on which they are called.



                  It always helps to write out the explicit call of an operator overload to better understand exactly what it does:



                  Foo<Bar> e (Bartrue);
                  Bar f = false;

                  // Pretty explicit: call the member function Foo<Bar>::operator==
                  if(e.operator ==(f)) /* ... */


                  This can't be confused with the comparison operator in Bar, because it would require an implicit conversion of the left-hand side, which is impossible.



                  You can trigger an ambiguity similar to the ones you see with the built-in types when you define Bar and its comparison operator like this:



                  struct Bar bool m; ;

                  // A free function allows conversion, this will be ambiguous:
                  bool operator==(const Bar&, const Bar&)

                  return false;



                  This is nicely demonstrated and explained in Scott Meyers's Effective C++, Item 24.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited 29 mins ago









                  Cody Gray

                  194k35382469




                  194k35382469










                  answered 3 hours ago









                  lubgrlubgr

                  13.8k32052




                  13.8k32052



























                      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%2f55249017%2fwhy-is-implicit-conversion-not-ambiguous-for-non-primitive-types%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

                      Are there any comparative studies done between Ashtavakra Gita and Buddhim?How is it wrong to believe that a self exists, or that it doesn't?Can you criticise or improve Ven. Bodhi's description of MahayanaWas the doctrine of 'Anatta', accepted as doctrine by modern Buddhism, actually taught by the Buddha?Relationship between Buddhism, Hinduism and Yoga?Comparison of Nirvana, Tao and Brahman/AtmaIs there a distinction between “ego identity” and “craving/hating”?Are there many differences between Taoism and Buddhism?Loss of “faith” in buddhismSimilarity between creation in Abrahamic religions and beginning of life in Earth mentioned Agganna Sutta?Are there studies about the difference between meditating in the morning versus in the evening?Can one follow Hinduism and Buddhism at the same time?Are there any prohibitions on participating in other religion's practices?Psychology of 'flow'

                      fallocate: fallocate failed: Text file busy in Ubuntu 17.04? Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)defragmenting and increasing performance of old lubuntu system with swap partitionIssue with increasing the root partition from the swapthis /usr/bin/dpkg returned error || ubuntu-16.04, 64bitDefault 17.04 swap file locationHow to Resize Ubuntu 17.04 Zesty Swap file size?Ubuntu freezes from online formsMy Laptop is not starting after upgrade ubuntu 16.04 (Kernel 4.8.0-38 to 04.10.0-36)hcp: ERROR: FALLOCATE FAILED!Not sure my swap is being usedWine 3.0 asking for more virtual free swap

                      Where is the suspend/hibernate button in GNOME Shell? Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 23:30 UTC (7:30pm US/Eastern)No suspend option in UI on Bionic BeaverHow can I set sleep mode in ubuntu18.04 LTS and what is the short cut key to do so?17.10 suspend not availableUbuntu 18.04 LTS missing sleep optionUbuntu 18.04 LTS - missing suspend option when power button is pressedHow to put Thinkpad X1 Extreme to sleep in Ubuntu 18.10?Suspend Button in interactive power button menu18.04 - Keep programs running after logging outway to disable Hibernate from within gconf-editor so button disappears?How can I hibernate from GNOME Shell?How can I hibernate/suspend from the command line and do so at a specific timeNo permission to suspend/hibernate after upgrading to 12.10MATE - Missing Suspend and Hibernate buttons, pressing power button shutdowns system immediatelyUbuntu 14.04: Suspend, Hibernate and Suspend-hybrid in the menu?Change “power-button-action” comand for “hibernate” option in GNOME 3.18Shutdown / Power off button does always go to suspend on 17.10Hibernate after suspend stopped working in 17.10Why doesn't the keyboard screenshot button work on Ubuntu with GNOME shell?