Non pre-declared function call works for class types but not primitive types

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











up vote
13
down vote

favorite
2












In the following code



template <typename T>
void foo(T)
bar(T);


class Something ;
void bar(Something)

int main()
foo(Something);



(https://wandbox.org/permlink/l2hxdZofLjZUoH4q)



When we call foo() with a Something parameter, everything works as expected, the call dispatches to the bar(Something) overload.



But when I change the argument to an integer and provide a bar(int) overload, I get an error



template <typename T>
void foo(T)
bar(T);


void bar(int)

int main()
foo(int);



Error:



error: call to function 'bar' that is neither visible in the template definition nor found by argument-dependent lookup


(https://wandbox.org/permlink/GI6wGlJYxGO4svEI)



In the class case, I have not defined bar() in a namespace along with the definition of Something. Meaning that I am not getting ADL. Then why does the code work with class types?







share|improve this question
















  • 1




    Global namespace counts as a namespace for the purposes of ADL.
    – HolyBlackCat
    Aug 18 at 7:00














up vote
13
down vote

favorite
2












In the following code



template <typename T>
void foo(T)
bar(T);


class Something ;
void bar(Something)

int main()
foo(Something);



(https://wandbox.org/permlink/l2hxdZofLjZUoH4q)



When we call foo() with a Something parameter, everything works as expected, the call dispatches to the bar(Something) overload.



But when I change the argument to an integer and provide a bar(int) overload, I get an error



template <typename T>
void foo(T)
bar(T);


void bar(int)

int main()
foo(int);



Error:



error: call to function 'bar' that is neither visible in the template definition nor found by argument-dependent lookup


(https://wandbox.org/permlink/GI6wGlJYxGO4svEI)



In the class case, I have not defined bar() in a namespace along with the definition of Something. Meaning that I am not getting ADL. Then why does the code work with class types?







share|improve this question
















  • 1




    Global namespace counts as a namespace for the purposes of ADL.
    – HolyBlackCat
    Aug 18 at 7:00












up vote
13
down vote

favorite
2









up vote
13
down vote

favorite
2






2





In the following code



template <typename T>
void foo(T)
bar(T);


class Something ;
void bar(Something)

int main()
foo(Something);



(https://wandbox.org/permlink/l2hxdZofLjZUoH4q)



When we call foo() with a Something parameter, everything works as expected, the call dispatches to the bar(Something) overload.



But when I change the argument to an integer and provide a bar(int) overload, I get an error



template <typename T>
void foo(T)
bar(T);


void bar(int)

int main()
foo(int);



Error:



error: call to function 'bar' that is neither visible in the template definition nor found by argument-dependent lookup


(https://wandbox.org/permlink/GI6wGlJYxGO4svEI)



In the class case, I have not defined bar() in a namespace along with the definition of Something. Meaning that I am not getting ADL. Then why does the code work with class types?







share|improve this question












In the following code



template <typename T>
void foo(T)
bar(T);


class Something ;
void bar(Something)

int main()
foo(Something);



(https://wandbox.org/permlink/l2hxdZofLjZUoH4q)



When we call foo() with a Something parameter, everything works as expected, the call dispatches to the bar(Something) overload.



But when I change the argument to an integer and provide a bar(int) overload, I get an error



template <typename T>
void foo(T)
bar(T);


void bar(int)

int main()
foo(int);



Error:



error: call to function 'bar' that is neither visible in the template definition nor found by argument-dependent lookup


(https://wandbox.org/permlink/GI6wGlJYxGO4svEI)



In the class case, I have not defined bar() in a namespace along with the definition of Something. Meaning that I am not getting ADL. Then why does the code work with class types?









share|improve this question











share|improve this question




share|improve this question










asked Aug 18 at 5:21









Curious

11.4k22366




11.4k22366







  • 1




    Global namespace counts as a namespace for the purposes of ADL.
    – HolyBlackCat
    Aug 18 at 7:00












  • 1




    Global namespace counts as a namespace for the purposes of ADL.
    – HolyBlackCat
    Aug 18 at 7:00







1




1




Global namespace counts as a namespace for the purposes of ADL.
– HolyBlackCat
Aug 18 at 7:00




Global namespace counts as a namespace for the purposes of ADL.
– HolyBlackCat
Aug 18 at 7:00












2 Answers
2






active

oldest

votes

















up vote
7
down vote














Then why does the code work with class types?




According to §6.4.2/2.1:




The sets of namespaces and classes are determined in the following
way:



  • If T is a fundamental type, its associated sets of namespaces and classes are both empty.



So upon writing foo(int), the compiler will have an empty set of namespaces and classes to be considered. The call to bar thus must fail, as it is not declared yet. If you declare foo(int) on beforehand, your code will compile:



void bar(int);

template <typename T>
void foo(T)
bar(T);


void bar(int)

int main()
foo(int);



On the other hand, in the case of the foo(Something), the (global) namespace will be part of the lookup, so the compiler actively scans the namespace for a function named bar that can be called with Something instances.






share|improve this answer





























    up vote
    4
    down vote













    Inside foo definition, bar is a dependent name because it is called with an argument that depends on a template parameter(T).



    Dependent name resolution is performed twice [temp.dep.res]:




    In resolving dependent names, names from the following sources are considered:



    • Declarations that are visible at the point of definition of the template.


    • Declarations from namespaces associated with the types of the function arguments both from the instantiation context ([temp.point]) and from the definition context.
      Bellow, comments show where is the point of instantiation:




    template <typename T>
    void foo(T) //point of definition of foo
    bar(T);


    class Something ;
    void bar(Something)
    void bar(int)

    int main()
    foo(int);
    foo(Something);

    //point of instantiation of foo<int>
    //point of instantiation of foo<Something>


    For foo<Something> and foo<int> no bar are visible from the point of definition.



    For foo<Something>, Something being a class its associated namespace is the namesapce in which it is declared: the global namespace. According to the second bullet, name look up is performed in the global namespace from the point of instantiation and bar(Something) is found.



    For foo<int>, int is a fundamental type and it has not any associated namespaces. So no name look up is performed from the point of instantiation, and bar<int> is thus not found.






    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
      );



      );








       

      draft saved


      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51905521%2fnon-pre-declared-function-call-works-for-class-types-but-not-primitive-types%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
      7
      down vote














      Then why does the code work with class types?




      According to §6.4.2/2.1:




      The sets of namespaces and classes are determined in the following
      way:



      • If T is a fundamental type, its associated sets of namespaces and classes are both empty.



      So upon writing foo(int), the compiler will have an empty set of namespaces and classes to be considered. The call to bar thus must fail, as it is not declared yet. If you declare foo(int) on beforehand, your code will compile:



      void bar(int);

      template <typename T>
      void foo(T)
      bar(T);


      void bar(int)

      int main()
      foo(int);



      On the other hand, in the case of the foo(Something), the (global) namespace will be part of the lookup, so the compiler actively scans the namespace for a function named bar that can be called with Something instances.






      share|improve this answer


























        up vote
        7
        down vote














        Then why does the code work with class types?




        According to §6.4.2/2.1:




        The sets of namespaces and classes are determined in the following
        way:



        • If T is a fundamental type, its associated sets of namespaces and classes are both empty.



        So upon writing foo(int), the compiler will have an empty set of namespaces and classes to be considered. The call to bar thus must fail, as it is not declared yet. If you declare foo(int) on beforehand, your code will compile:



        void bar(int);

        template <typename T>
        void foo(T)
        bar(T);


        void bar(int)

        int main()
        foo(int);



        On the other hand, in the case of the foo(Something), the (global) namespace will be part of the lookup, so the compiler actively scans the namespace for a function named bar that can be called with Something instances.






        share|improve this answer
























          up vote
          7
          down vote










          up vote
          7
          down vote










          Then why does the code work with class types?




          According to §6.4.2/2.1:




          The sets of namespaces and classes are determined in the following
          way:



          • If T is a fundamental type, its associated sets of namespaces and classes are both empty.



          So upon writing foo(int), the compiler will have an empty set of namespaces and classes to be considered. The call to bar thus must fail, as it is not declared yet. If you declare foo(int) on beforehand, your code will compile:



          void bar(int);

          template <typename T>
          void foo(T)
          bar(T);


          void bar(int)

          int main()
          foo(int);



          On the other hand, in the case of the foo(Something), the (global) namespace will be part of the lookup, so the compiler actively scans the namespace for a function named bar that can be called with Something instances.






          share|improve this answer















          Then why does the code work with class types?




          According to §6.4.2/2.1:




          The sets of namespaces and classes are determined in the following
          way:



          • If T is a fundamental type, its associated sets of namespaces and classes are both empty.



          So upon writing foo(int), the compiler will have an empty set of namespaces and classes to be considered. The call to bar thus must fail, as it is not declared yet. If you declare foo(int) on beforehand, your code will compile:



          void bar(int);

          template <typename T>
          void foo(T)
          bar(T);


          void bar(int)

          int main()
          foo(int);



          On the other hand, in the case of the foo(Something), the (global) namespace will be part of the lookup, so the compiler actively scans the namespace for a function named bar that can be called with Something instances.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Aug 18 at 7:55

























          answered Aug 18 at 6:55









          Jodocus

          5,1601835




          5,1601835






















              up vote
              4
              down vote













              Inside foo definition, bar is a dependent name because it is called with an argument that depends on a template parameter(T).



              Dependent name resolution is performed twice [temp.dep.res]:




              In resolving dependent names, names from the following sources are considered:



              • Declarations that are visible at the point of definition of the template.


              • Declarations from namespaces associated with the types of the function arguments both from the instantiation context ([temp.point]) and from the definition context.
                Bellow, comments show where is the point of instantiation:




              template <typename T>
              void foo(T) //point of definition of foo
              bar(T);


              class Something ;
              void bar(Something)
              void bar(int)

              int main()
              foo(int);
              foo(Something);

              //point of instantiation of foo<int>
              //point of instantiation of foo<Something>


              For foo<Something> and foo<int> no bar are visible from the point of definition.



              For foo<Something>, Something being a class its associated namespace is the namesapce in which it is declared: the global namespace. According to the second bullet, name look up is performed in the global namespace from the point of instantiation and bar(Something) is found.



              For foo<int>, int is a fundamental type and it has not any associated namespaces. So no name look up is performed from the point of instantiation, and bar<int> is thus not found.






              share|improve this answer
























                up vote
                4
                down vote













                Inside foo definition, bar is a dependent name because it is called with an argument that depends on a template parameter(T).



                Dependent name resolution is performed twice [temp.dep.res]:




                In resolving dependent names, names from the following sources are considered:



                • Declarations that are visible at the point of definition of the template.


                • Declarations from namespaces associated with the types of the function arguments both from the instantiation context ([temp.point]) and from the definition context.
                  Bellow, comments show where is the point of instantiation:




                template <typename T>
                void foo(T) //point of definition of foo
                bar(T);


                class Something ;
                void bar(Something)
                void bar(int)

                int main()
                foo(int);
                foo(Something);

                //point of instantiation of foo<int>
                //point of instantiation of foo<Something>


                For foo<Something> and foo<int> no bar are visible from the point of definition.



                For foo<Something>, Something being a class its associated namespace is the namesapce in which it is declared: the global namespace. According to the second bullet, name look up is performed in the global namespace from the point of instantiation and bar(Something) is found.



                For foo<int>, int is a fundamental type and it has not any associated namespaces. So no name look up is performed from the point of instantiation, and bar<int> is thus not found.






                share|improve this answer






















                  up vote
                  4
                  down vote










                  up vote
                  4
                  down vote









                  Inside foo definition, bar is a dependent name because it is called with an argument that depends on a template parameter(T).



                  Dependent name resolution is performed twice [temp.dep.res]:




                  In resolving dependent names, names from the following sources are considered:



                  • Declarations that are visible at the point of definition of the template.


                  • Declarations from namespaces associated with the types of the function arguments both from the instantiation context ([temp.point]) and from the definition context.
                    Bellow, comments show where is the point of instantiation:




                  template <typename T>
                  void foo(T) //point of definition of foo
                  bar(T);


                  class Something ;
                  void bar(Something)
                  void bar(int)

                  int main()
                  foo(int);
                  foo(Something);

                  //point of instantiation of foo<int>
                  //point of instantiation of foo<Something>


                  For foo<Something> and foo<int> no bar are visible from the point of definition.



                  For foo<Something>, Something being a class its associated namespace is the namesapce in which it is declared: the global namespace. According to the second bullet, name look up is performed in the global namespace from the point of instantiation and bar(Something) is found.



                  For foo<int>, int is a fundamental type and it has not any associated namespaces. So no name look up is performed from the point of instantiation, and bar<int> is thus not found.






                  share|improve this answer












                  Inside foo definition, bar is a dependent name because it is called with an argument that depends on a template parameter(T).



                  Dependent name resolution is performed twice [temp.dep.res]:




                  In resolving dependent names, names from the following sources are considered:



                  • Declarations that are visible at the point of definition of the template.


                  • Declarations from namespaces associated with the types of the function arguments both from the instantiation context ([temp.point]) and from the definition context.
                    Bellow, comments show where is the point of instantiation:




                  template <typename T>
                  void foo(T) //point of definition of foo
                  bar(T);


                  class Something ;
                  void bar(Something)
                  void bar(int)

                  int main()
                  foo(int);
                  foo(Something);

                  //point of instantiation of foo<int>
                  //point of instantiation of foo<Something>


                  For foo<Something> and foo<int> no bar are visible from the point of definition.



                  For foo<Something>, Something being a class its associated namespace is the namesapce in which it is declared: the global namespace. According to the second bullet, name look up is performed in the global namespace from the point of instantiation and bar(Something) is found.



                  For foo<int>, int is a fundamental type and it has not any associated namespaces. So no name look up is performed from the point of instantiation, and bar<int> is thus not found.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Aug 18 at 7:33









                  Oliv

                  6,4131747




                  6,4131747






















                       

                      draft saved


                      draft discarded


























                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51905521%2fnon-pre-declared-function-call-works-for-class-types-but-not-primitive-types%23new-answer', 'question_page');

                      );

                      Post as a guest













































































                      這個網誌中的熱門文章

                      How to combine Bézier curves to a surface?

                      Mutual Information Always Non-negative

                      Why am i infinitely getting the same tweet with the Twitter Search API?