Overload resolution looking into namespaces











up vote
28
down vote

favorite
5












The following code fails as expected, because no overload of get is found. Using std::getwould solve the problem.



#include <array>

int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//fails, get was not declared in this scope
}


However, introducing a templated version of get, even though it's not matching the function call, somehow makes the compiler use the std::get version:



#include <array>

template <typename T>
void get(){};

int main()
{
std::array<int, 2> ar{2,3};

auto r = get<0>(ar);//returns 2
}


I can't find any part of the standard that explains this. Is this a bug in all 3 compilers I tested (probably not), or am I missing something?



This behaviour was tested in




  • MSVC 15.9.2

  • Clang 8.0.0

  • GCC 9.0.0 (still an experimental version)


EDIT:
I am aware of ADL. But if ADL makes the second code work, why does it not in the first part?










share|improve this question
























  • It is found by ADL. Seems that ADL is prevented without providing that declaration, .
    – felix
    2 days ago






  • 1




    I was suspecting ADL. However, it does not explain why ADL doesn't work without the fake-template
    – LcdDrm
    2 days ago










  • Alternatively, just don't give your functions names that are already within the standard library.
    – jfh
    2 days ago






  • 1




    @jfh Bad advice. Don’t try to work around something that namespaces already fix for you.
    – Konrad Rudolph
    2 days ago










  • @KonradRudolph For most cases yes of course use a namespace (preferably not the global one), but I expect functions and classes named after standard counterparts to do the same thing and perform the exact same way (if it ain't broke...). I would use a fully qualified name for a function, and honestly fail someone's code review if they used a mirrored name and didn't explain clearly why. Granted this has no bearing on the original question which is why this is a comment.
    – jfh
    2 days ago















up vote
28
down vote

favorite
5












The following code fails as expected, because no overload of get is found. Using std::getwould solve the problem.



#include <array>

int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//fails, get was not declared in this scope
}


However, introducing a templated version of get, even though it's not matching the function call, somehow makes the compiler use the std::get version:



#include <array>

template <typename T>
void get(){};

int main()
{
std::array<int, 2> ar{2,3};

auto r = get<0>(ar);//returns 2
}


I can't find any part of the standard that explains this. Is this a bug in all 3 compilers I tested (probably not), or am I missing something?



This behaviour was tested in




  • MSVC 15.9.2

  • Clang 8.0.0

  • GCC 9.0.0 (still an experimental version)


EDIT:
I am aware of ADL. But if ADL makes the second code work, why does it not in the first part?










share|improve this question
























  • It is found by ADL. Seems that ADL is prevented without providing that declaration, .
    – felix
    2 days ago






  • 1




    I was suspecting ADL. However, it does not explain why ADL doesn't work without the fake-template
    – LcdDrm
    2 days ago










  • Alternatively, just don't give your functions names that are already within the standard library.
    – jfh
    2 days ago






  • 1




    @jfh Bad advice. Don’t try to work around something that namespaces already fix for you.
    – Konrad Rudolph
    2 days ago










  • @KonradRudolph For most cases yes of course use a namespace (preferably not the global one), but I expect functions and classes named after standard counterparts to do the same thing and perform the exact same way (if it ain't broke...). I would use a fully qualified name for a function, and honestly fail someone's code review if they used a mirrored name and didn't explain clearly why. Granted this has no bearing on the original question which is why this is a comment.
    – jfh
    2 days ago













up vote
28
down vote

favorite
5









up vote
28
down vote

favorite
5






5





The following code fails as expected, because no overload of get is found. Using std::getwould solve the problem.



#include <array>

int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//fails, get was not declared in this scope
}


However, introducing a templated version of get, even though it's not matching the function call, somehow makes the compiler use the std::get version:



#include <array>

template <typename T>
void get(){};

int main()
{
std::array<int, 2> ar{2,3};

auto r = get<0>(ar);//returns 2
}


I can't find any part of the standard that explains this. Is this a bug in all 3 compilers I tested (probably not), or am I missing something?



This behaviour was tested in




  • MSVC 15.9.2

  • Clang 8.0.0

  • GCC 9.0.0 (still an experimental version)


EDIT:
I am aware of ADL. But if ADL makes the second code work, why does it not in the first part?










share|improve this question















The following code fails as expected, because no overload of get is found. Using std::getwould solve the problem.



#include <array>

int main()
{
std::array<int, 2> ar{2,3};
auto r = get<0>(ar);//fails, get was not declared in this scope
}


However, introducing a templated version of get, even though it's not matching the function call, somehow makes the compiler use the std::get version:



#include <array>

template <typename T>
void get(){};

int main()
{
std::array<int, 2> ar{2,3};

auto r = get<0>(ar);//returns 2
}


I can't find any part of the standard that explains this. Is this a bug in all 3 compilers I tested (probably not), or am I missing something?



This behaviour was tested in




  • MSVC 15.9.2

  • Clang 8.0.0

  • GCC 9.0.0 (still an experimental version)


EDIT:
I am aware of ADL. But if ADL makes the second code work, why does it not in the first part?







c++ overload-resolution






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 2 days ago

























asked 2 days ago









LcdDrm

532411




532411












  • It is found by ADL. Seems that ADL is prevented without providing that declaration, .
    – felix
    2 days ago






  • 1




    I was suspecting ADL. However, it does not explain why ADL doesn't work without the fake-template
    – LcdDrm
    2 days ago










  • Alternatively, just don't give your functions names that are already within the standard library.
    – jfh
    2 days ago






  • 1




    @jfh Bad advice. Don’t try to work around something that namespaces already fix for you.
    – Konrad Rudolph
    2 days ago










  • @KonradRudolph For most cases yes of course use a namespace (preferably not the global one), but I expect functions and classes named after standard counterparts to do the same thing and perform the exact same way (if it ain't broke...). I would use a fully qualified name for a function, and honestly fail someone's code review if they used a mirrored name and didn't explain clearly why. Granted this has no bearing on the original question which is why this is a comment.
    – jfh
    2 days ago


















  • It is found by ADL. Seems that ADL is prevented without providing that declaration, .
    – felix
    2 days ago






  • 1




    I was suspecting ADL. However, it does not explain why ADL doesn't work without the fake-template
    – LcdDrm
    2 days ago










  • Alternatively, just don't give your functions names that are already within the standard library.
    – jfh
    2 days ago






  • 1




    @jfh Bad advice. Don’t try to work around something that namespaces already fix for you.
    – Konrad Rudolph
    2 days ago










  • @KonradRudolph For most cases yes of course use a namespace (preferably not the global one), but I expect functions and classes named after standard counterparts to do the same thing and perform the exact same way (if it ain't broke...). I would use a fully qualified name for a function, and honestly fail someone's code review if they used a mirrored name and didn't explain clearly why. Granted this has no bearing on the original question which is why this is a comment.
    – jfh
    2 days ago
















It is found by ADL. Seems that ADL is prevented without providing that declaration, .
– felix
2 days ago




It is found by ADL. Seems that ADL is prevented without providing that declaration, .
– felix
2 days ago




1




1




I was suspecting ADL. However, it does not explain why ADL doesn't work without the fake-template
– LcdDrm
2 days ago




I was suspecting ADL. However, it does not explain why ADL doesn't work without the fake-template
– LcdDrm
2 days ago












Alternatively, just don't give your functions names that are already within the standard library.
– jfh
2 days ago




Alternatively, just don't give your functions names that are already within the standard library.
– jfh
2 days ago




1




1




@jfh Bad advice. Don’t try to work around something that namespaces already fix for you.
– Konrad Rudolph
2 days ago




@jfh Bad advice. Don’t try to work around something that namespaces already fix for you.
– Konrad Rudolph
2 days ago












@KonradRudolph For most cases yes of course use a namespace (preferably not the global one), but I expect functions and classes named after standard counterparts to do the same thing and perform the exact same way (if it ain't broke...). I would use a fully qualified name for a function, and honestly fail someone's code review if they used a mirrored name and didn't explain clearly why. Granted this has no bearing on the original question which is why this is a comment.
– jfh
2 days ago




@KonradRudolph For most cases yes of course use a namespace (preferably not the global one), but I expect functions and classes named after standard counterparts to do the same thing and perform the exact same way (if it ain't broke...). I would use a fully qualified name for a function, and honestly fail someone's code review if they used a mirrored name and didn't explain clearly why. Granted this has no bearing on the original question which is why this is a comment.
– jfh
2 days ago












2 Answers
2






active

oldest

votes

















up vote
18
down vote



accepted










ADL is not used when explicit template arguments are involved unless you introduce a template function declaration at the call point. You're using an unqualified form of get using a non-type template argument 0, so you need to introduce a template function declaration or use the qualified version of get as std::get<0>(ar).



In standardese [temp.arg.explicit]/8: (emphasis mine)




[ Note: For simple function names, argument dependent lookup (6.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (6.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.




EDIT:



As @Yakk - Adam Nevraumont has pointed out in the comment, without the presence of the template function declaration, the expression get<0>(ar) will be parsed as (get<0)>(ar), i.e as a serie of comparison expressions instead of a function call.






share|improve this answer























  • Well that makes sense. Although in GCC 9.0.0, a void get(); is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?
    – LcdDrm
    2 days ago












  • That version of GCC is still under development, its too early to say that
    – Jans
    2 days ago






  • 5




    Good answer, but I'd mention what get<0>(ar) is parsed as without the template: (get<0)>(ar). This makes it more clear why the existence of the template get makes a difference.
    – Yakk - Adam Nevraumont
    2 days ago




















up vote
4
down vote













Note that this changed in C++20 as a result of P0846R0. An unqualified name followed by a < token for which ordinary unqualified lookup either finds one or more functions or finds nothing is now assumed to name a template and the < is parsed accordingly.






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: 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%2f53393467%2foverload-resolution-looking-into-namespaces%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








    up vote
    18
    down vote



    accepted










    ADL is not used when explicit template arguments are involved unless you introduce a template function declaration at the call point. You're using an unqualified form of get using a non-type template argument 0, so you need to introduce a template function declaration or use the qualified version of get as std::get<0>(ar).



    In standardese [temp.arg.explicit]/8: (emphasis mine)




    [ Note: For simple function names, argument dependent lookup (6.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (6.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.




    EDIT:



    As @Yakk - Adam Nevraumont has pointed out in the comment, without the presence of the template function declaration, the expression get<0>(ar) will be parsed as (get<0)>(ar), i.e as a serie of comparison expressions instead of a function call.






    share|improve this answer























    • Well that makes sense. Although in GCC 9.0.0, a void get(); is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?
      – LcdDrm
      2 days ago












    • That version of GCC is still under development, its too early to say that
      – Jans
      2 days ago






    • 5




      Good answer, but I'd mention what get<0>(ar) is parsed as without the template: (get<0)>(ar). This makes it more clear why the existence of the template get makes a difference.
      – Yakk - Adam Nevraumont
      2 days ago

















    up vote
    18
    down vote



    accepted










    ADL is not used when explicit template arguments are involved unless you introduce a template function declaration at the call point. You're using an unqualified form of get using a non-type template argument 0, so you need to introduce a template function declaration or use the qualified version of get as std::get<0>(ar).



    In standardese [temp.arg.explicit]/8: (emphasis mine)




    [ Note: For simple function names, argument dependent lookup (6.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (6.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.




    EDIT:



    As @Yakk - Adam Nevraumont has pointed out in the comment, without the presence of the template function declaration, the expression get<0>(ar) will be parsed as (get<0)>(ar), i.e as a serie of comparison expressions instead of a function call.






    share|improve this answer























    • Well that makes sense. Although in GCC 9.0.0, a void get(); is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?
      – LcdDrm
      2 days ago












    • That version of GCC is still under development, its too early to say that
      – Jans
      2 days ago






    • 5




      Good answer, but I'd mention what get<0>(ar) is parsed as without the template: (get<0)>(ar). This makes it more clear why the existence of the template get makes a difference.
      – Yakk - Adam Nevraumont
      2 days ago















    up vote
    18
    down vote



    accepted







    up vote
    18
    down vote



    accepted






    ADL is not used when explicit template arguments are involved unless you introduce a template function declaration at the call point. You're using an unqualified form of get using a non-type template argument 0, so you need to introduce a template function declaration or use the qualified version of get as std::get<0>(ar).



    In standardese [temp.arg.explicit]/8: (emphasis mine)




    [ Note: For simple function names, argument dependent lookup (6.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (6.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.




    EDIT:



    As @Yakk - Adam Nevraumont has pointed out in the comment, without the presence of the template function declaration, the expression get<0>(ar) will be parsed as (get<0)>(ar), i.e as a serie of comparison expressions instead of a function call.






    share|improve this answer














    ADL is not used when explicit template arguments are involved unless you introduce a template function declaration at the call point. You're using an unqualified form of get using a non-type template argument 0, so you need to introduce a template function declaration or use the qualified version of get as std::get<0>(ar).



    In standardese [temp.arg.explicit]/8: (emphasis mine)




    [ Note: For simple function names, argument dependent lookup (6.4.2) applies even when the function name is not visible within the scope of the call. This is because the call still has the syntactic form of a function call (6.4.1). But when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply. If some such name is visible, argument dependent lookup applies and additional function templates may be found in other namespaces.




    EDIT:



    As @Yakk - Adam Nevraumont has pointed out in the comment, without the presence of the template function declaration, the expression get<0>(ar) will be parsed as (get<0)>(ar), i.e as a serie of comparison expressions instead of a function call.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited yesterday

























    answered 2 days ago









    Jans

    6,09612233




    6,09612233












    • Well that makes sense. Although in GCC 9.0.0, a void get(); is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?
      – LcdDrm
      2 days ago












    • That version of GCC is still under development, its too early to say that
      – Jans
      2 days ago






    • 5




      Good answer, but I'd mention what get<0>(ar) is parsed as without the template: (get<0)>(ar). This makes it more clear why the existence of the template get makes a difference.
      – Yakk - Adam Nevraumont
      2 days ago




















    • Well that makes sense. Although in GCC 9.0.0, a void get(); is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?
      – LcdDrm
      2 days ago












    • That version of GCC is still under development, its too early to say that
      – Jans
      2 days ago






    • 5




      Good answer, but I'd mention what get<0>(ar) is parsed as without the template: (get<0)>(ar). This makes it more clear why the existence of the template get makes a difference.
      – Yakk - Adam Nevraumont
      2 days ago


















    Well that makes sense. Although in GCC 9.0.0, a void get(); is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?
    – LcdDrm
    2 days ago






    Well that makes sense. Although in GCC 9.0.0, a void get(); is enough to make ADL work again. If I interpret that snipped of the standard correctly, this is a compiler bug?
    – LcdDrm
    2 days ago














    That version of GCC is still under development, its too early to say that
    – Jans
    2 days ago




    That version of GCC is still under development, its too early to say that
    – Jans
    2 days ago




    5




    5




    Good answer, but I'd mention what get<0>(ar) is parsed as without the template: (get<0)>(ar). This makes it more clear why the existence of the template get makes a difference.
    – Yakk - Adam Nevraumont
    2 days ago






    Good answer, but I'd mention what get<0>(ar) is parsed as without the template: (get<0)>(ar). This makes it more clear why the existence of the template get makes a difference.
    – Yakk - Adam Nevraumont
    2 days ago














    up vote
    4
    down vote













    Note that this changed in C++20 as a result of P0846R0. An unqualified name followed by a < token for which ordinary unqualified lookup either finds one or more functions or finds nothing is now assumed to name a template and the < is parsed accordingly.






    share|improve this answer

























      up vote
      4
      down vote













      Note that this changed in C++20 as a result of P0846R0. An unqualified name followed by a < token for which ordinary unqualified lookup either finds one or more functions or finds nothing is now assumed to name a template and the < is parsed accordingly.






      share|improve this answer























        up vote
        4
        down vote










        up vote
        4
        down vote









        Note that this changed in C++20 as a result of P0846R0. An unqualified name followed by a < token for which ordinary unqualified lookup either finds one or more functions or finds nothing is now assumed to name a template and the < is parsed accordingly.






        share|improve this answer












        Note that this changed in C++20 as a result of P0846R0. An unqualified name followed by a < token for which ordinary unqualified lookup either finds one or more functions or finds nothing is now assumed to name a template and the < is parsed accordingly.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 2 days ago









        T.C.

        104k13212317




        104k13212317






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53393467%2foverload-resolution-looking-into-namespaces%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

            "Incorrect syntax near the keyword 'ON'. (on update cascade, on delete cascade,)

            Alcedinidae

            Origin of the phrase “under your belt”?