Why isn't this call to a template ambiguous?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
12
down vote

favorite












I declare two templates, the first converts the argument x from type T to type U and the second from type U to type T. If I call cast with 10, the compiler does not complain. I think both meet the requirements to be used and therefore there should be ambiguity, is that true? This code prints 10.



#include <iostream>

template<typename T, typename U>
U cast(T x)
return static_cast<U>(x);


template<typename T, typename U>
T cast(U x)
return static_cast<T>(x);


int main()
std::cout << cast<int,float>(10) << 'n';










share|improve this question









New contributor




wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.



















  • If you change your code to cast<int,float>(10.0f) the second overload would be called. And if you changed it to cast<int,float>(10.0) the call would be ambiguous.
    – Praetorian
    5 hours ago














up vote
12
down vote

favorite












I declare two templates, the first converts the argument x from type T to type U and the second from type U to type T. If I call cast with 10, the compiler does not complain. I think both meet the requirements to be used and therefore there should be ambiguity, is that true? This code prints 10.



#include <iostream>

template<typename T, typename U>
U cast(T x)
return static_cast<U>(x);


template<typename T, typename U>
T cast(U x)
return static_cast<T>(x);


int main()
std::cout << cast<int,float>(10) << 'n';










share|improve this question









New contributor




wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.



















  • If you change your code to cast<int,float>(10.0f) the second overload would be called. And if you changed it to cast<int,float>(10.0) the call would be ambiguous.
    – Praetorian
    5 hours ago












up vote
12
down vote

favorite









up vote
12
down vote

favorite











I declare two templates, the first converts the argument x from type T to type U and the second from type U to type T. If I call cast with 10, the compiler does not complain. I think both meet the requirements to be used and therefore there should be ambiguity, is that true? This code prints 10.



#include <iostream>

template<typename T, typename U>
U cast(T x)
return static_cast<U>(x);


template<typename T, typename U>
T cast(U x)
return static_cast<T>(x);


int main()
std::cout << cast<int,float>(10) << 'n';










share|improve this question









New contributor




wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











I declare two templates, the first converts the argument x from type T to type U and the second from type U to type T. If I call cast with 10, the compiler does not complain. I think both meet the requirements to be used and therefore there should be ambiguity, is that true? This code prints 10.



#include <iostream>

template<typename T, typename U>
U cast(T x)
return static_cast<U>(x);


template<typename T, typename U>
T cast(U x)
return static_cast<T>(x);


int main()
std::cout << cast<int,float>(10) << 'n';







c++ templates overload-resolution template-deduction






share|improve this question









New contributor




wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 12 mins ago









Deduplicator

33.2k64786




33.2k64786






New contributor




wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 6 hours ago









wic

1087




1087




New contributor




wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






wic is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











  • If you change your code to cast<int,float>(10.0f) the second overload would be called. And if you changed it to cast<int,float>(10.0) the call would be ambiguous.
    – Praetorian
    5 hours ago
















  • If you change your code to cast<int,float>(10.0f) the second overload would be called. And if you changed it to cast<int,float>(10.0) the call would be ambiguous.
    – Praetorian
    5 hours ago















If you change your code to cast<int,float>(10.0f) the second overload would be called. And if you changed it to cast<int,float>(10.0) the call would be ambiguous.
– Praetorian
5 hours ago




If you change your code to cast<int,float>(10.0f) the second overload would be called. And if you changed it to cast<int,float>(10.0) the call would be ambiguous.
– Praetorian
5 hours ago












2 Answers
2






active

oldest

votes

















up vote
21
down vote



accepted










When you use cast<int, float>, both templates are considered.



template<typename T=int,typename U=float>
U cast(T x);
template<typename T=int,typename U=float>
T cast(U x);


we then substitute:



template<typename T=int,typename U=float>
float cast(int x);
template<typename T=int,typename U=float>
int cast(float x);


at this point, there are no types to deduce. So we go to overload resolution.



In one case, we can take an int and convert to float when calling cast, and in the other we take a int and convert to int when calling cast. Note I'm not looking at all into the body of cast; the body is not relevant to overload resolution.



The second non-conversion (at the point of call) is a better match, so that overload is chosen.



If you did this:



std::cout << cast<int>(10) << "n";


things get more interesting:



template<typename T=int,typename U=?>
U cast(T x);
template<typename T=int,typename U=?>
T cast(U x);


for the first one, we cannot deduce U. For the second one we can.



template<typename T=int,typename U=?>
U cast(int x);
template<typename T=int,typename U=int>
int cast(int x);


so here we have one viable overload, and it is used.






share|improve this answer






















  • what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
    – jakub_d
    5 hours ago






  • 1




    @jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
    – Yakk - Adam Nevraumont
    5 hours ago


















up vote
2
down vote













The instantiation is not ambiguous because the function argument exactly matches the first template parameter: the literal 10 is an int, which is also explicitly specified for the first template type.



You can make the instantiation ambiguous when the argument type does not match the explicitly specified types (thus, a conversion is necessary), e.g.



// error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
std::cout << cast<int,float>(10u) << "n";





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',
    convertImagesToLinks: true,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );






    wic is a new contributor. Be nice, and check out our Code of Conduct.









     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52609797%2fwhy-isnt-this-call-to-a-template-ambiguous%23new-answer', 'question_page');

    );

    Post as a guest






























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    21
    down vote



    accepted










    When you use cast<int, float>, both templates are considered.



    template<typename T=int,typename U=float>
    U cast(T x);
    template<typename T=int,typename U=float>
    T cast(U x);


    we then substitute:



    template<typename T=int,typename U=float>
    float cast(int x);
    template<typename T=int,typename U=float>
    int cast(float x);


    at this point, there are no types to deduce. So we go to overload resolution.



    In one case, we can take an int and convert to float when calling cast, and in the other we take a int and convert to int when calling cast. Note I'm not looking at all into the body of cast; the body is not relevant to overload resolution.



    The second non-conversion (at the point of call) is a better match, so that overload is chosen.



    If you did this:



    std::cout << cast<int>(10) << "n";


    things get more interesting:



    template<typename T=int,typename U=?>
    U cast(T x);
    template<typename T=int,typename U=?>
    T cast(U x);


    for the first one, we cannot deduce U. For the second one we can.



    template<typename T=int,typename U=?>
    U cast(int x);
    template<typename T=int,typename U=int>
    int cast(int x);


    so here we have one viable overload, and it is used.






    share|improve this answer






















    • what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
      – jakub_d
      5 hours ago






    • 1




      @jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
      – Yakk - Adam Nevraumont
      5 hours ago















    up vote
    21
    down vote



    accepted










    When you use cast<int, float>, both templates are considered.



    template<typename T=int,typename U=float>
    U cast(T x);
    template<typename T=int,typename U=float>
    T cast(U x);


    we then substitute:



    template<typename T=int,typename U=float>
    float cast(int x);
    template<typename T=int,typename U=float>
    int cast(float x);


    at this point, there are no types to deduce. So we go to overload resolution.



    In one case, we can take an int and convert to float when calling cast, and in the other we take a int and convert to int when calling cast. Note I'm not looking at all into the body of cast; the body is not relevant to overload resolution.



    The second non-conversion (at the point of call) is a better match, so that overload is chosen.



    If you did this:



    std::cout << cast<int>(10) << "n";


    things get more interesting:



    template<typename T=int,typename U=?>
    U cast(T x);
    template<typename T=int,typename U=?>
    T cast(U x);


    for the first one, we cannot deduce U. For the second one we can.



    template<typename T=int,typename U=?>
    U cast(int x);
    template<typename T=int,typename U=int>
    int cast(int x);


    so here we have one viable overload, and it is used.






    share|improve this answer






















    • what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
      – jakub_d
      5 hours ago






    • 1




      @jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
      – Yakk - Adam Nevraumont
      5 hours ago













    up vote
    21
    down vote



    accepted







    up vote
    21
    down vote



    accepted






    When you use cast<int, float>, both templates are considered.



    template<typename T=int,typename U=float>
    U cast(T x);
    template<typename T=int,typename U=float>
    T cast(U x);


    we then substitute:



    template<typename T=int,typename U=float>
    float cast(int x);
    template<typename T=int,typename U=float>
    int cast(float x);


    at this point, there are no types to deduce. So we go to overload resolution.



    In one case, we can take an int and convert to float when calling cast, and in the other we take a int and convert to int when calling cast. Note I'm not looking at all into the body of cast; the body is not relevant to overload resolution.



    The second non-conversion (at the point of call) is a better match, so that overload is chosen.



    If you did this:



    std::cout << cast<int>(10) << "n";


    things get more interesting:



    template<typename T=int,typename U=?>
    U cast(T x);
    template<typename T=int,typename U=?>
    T cast(U x);


    for the first one, we cannot deduce U. For the second one we can.



    template<typename T=int,typename U=?>
    U cast(int x);
    template<typename T=int,typename U=int>
    int cast(int x);


    so here we have one viable overload, and it is used.






    share|improve this answer














    When you use cast<int, float>, both templates are considered.



    template<typename T=int,typename U=float>
    U cast(T x);
    template<typename T=int,typename U=float>
    T cast(U x);


    we then substitute:



    template<typename T=int,typename U=float>
    float cast(int x);
    template<typename T=int,typename U=float>
    int cast(float x);


    at this point, there are no types to deduce. So we go to overload resolution.



    In one case, we can take an int and convert to float when calling cast, and in the other we take a int and convert to int when calling cast. Note I'm not looking at all into the body of cast; the body is not relevant to overload resolution.



    The second non-conversion (at the point of call) is a better match, so that overload is chosen.



    If you did this:



    std::cout << cast<int>(10) << "n";


    things get more interesting:



    template<typename T=int,typename U=?>
    U cast(T x);
    template<typename T=int,typename U=?>
    T cast(U x);


    for the first one, we cannot deduce U. For the second one we can.



    template<typename T=int,typename U=?>
    U cast(int x);
    template<typename T=int,typename U=int>
    int cast(int x);


    so here we have one viable overload, and it is used.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 5 hours ago

























    answered 5 hours ago









    Yakk - Adam Nevraumont

    172k18175354




    172k18175354











    • what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
      – jakub_d
      5 hours ago






    • 1




      @jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
      – Yakk - Adam Nevraumont
      5 hours ago

















    • what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
      – jakub_d
      5 hours ago






    • 1




      @jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
      – Yakk - Adam Nevraumont
      5 hours ago
















    what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
    – jakub_d
    5 hours ago




    what OP's code actually does is convert from int to float (verified in assembler), so what non-conversion?
    – jakub_d
    5 hours ago




    1




    1




    @jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
    – Yakk - Adam Nevraumont
    5 hours ago





    @jakub_d In the overload resolution of the argument. The body of a function does not change which function is called.
    – Yakk - Adam Nevraumont
    5 hours ago













    up vote
    2
    down vote













    The instantiation is not ambiguous because the function argument exactly matches the first template parameter: the literal 10 is an int, which is also explicitly specified for the first template type.



    You can make the instantiation ambiguous when the argument type does not match the explicitly specified types (thus, a conversion is necessary), e.g.



    // error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
    std::cout << cast<int,float>(10u) << "n";





    share|improve this answer
























      up vote
      2
      down vote













      The instantiation is not ambiguous because the function argument exactly matches the first template parameter: the literal 10 is an int, which is also explicitly specified for the first template type.



      You can make the instantiation ambiguous when the argument type does not match the explicitly specified types (thus, a conversion is necessary), e.g.



      // error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
      std::cout << cast<int,float>(10u) << "n";





      share|improve this answer






















        up vote
        2
        down vote










        up vote
        2
        down vote









        The instantiation is not ambiguous because the function argument exactly matches the first template parameter: the literal 10 is an int, which is also explicitly specified for the first template type.



        You can make the instantiation ambiguous when the argument type does not match the explicitly specified types (thus, a conversion is necessary), e.g.



        // error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
        std::cout << cast<int,float>(10u) << "n";





        share|improve this answer












        The instantiation is not ambiguous because the function argument exactly matches the first template parameter: the literal 10 is an int, which is also explicitly specified for the first template type.



        You can make the instantiation ambiguous when the argument type does not match the explicitly specified types (thus, a conversion is necessary), e.g.



        // error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
        std::cout << cast<int,float>(10u) << "n";






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 5 hours ago









        lubgr

        7,64521442




        7,64521442




















            wic is a new contributor. Be nice, and check out our Code of Conduct.









             

            draft saved


            draft discarded


















            wic is a new contributor. Be nice, and check out our Code of Conduct.












            wic is a new contributor. Be nice, and check out our Code of Conduct.











            wic is a new contributor. Be nice, and check out our Code of Conduct.













             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52609797%2fwhy-isnt-this-call-to-a-template-ambiguous%23new-answer', 'question_page');

            );

            Post as a guest













































































            Comments

            Popular posts from this blog

            Long meetings (6-7 hours a day): Being “babysat” by supervisor

            Is the Concept of Multiple Fantasy Races Scientifically Flawed? [closed]

            Confectionery