Function template and regular overloads

Multi tool use
Multi tool use












2















The following code has a couple of regular function overloads, and - now - a template function intended as a catch-all if no overload is suitable.



It almost works as I want, except that using derived classes (which previously ended up in the regular overload) get handled by the function template instead.



#include <iostream>

class Base { };
class AnotherBase { };

class Derv : public Base{ };

class Derv2 : public Base { };

class DervDerv : public Derv { };

void f(const Base &b)
{
printf("b(Base)n");
}

void f(const Derv &b)
{
printf("b(Derv)n");
}

template<class T> void f(const T& t)
{
printf("b(template)n");
}

int main() {
f(Base());
f(AnotherBase());
f(Derv());
f(Derv2());
f(DervDerv());

return 0;
}


So the output I get is this...



b(Base)
b(template)
b(Derv)
b(template)
b(template)


... when what I'd naively expected was this:



b(Base)
b(template)
b(Derv)
b(Base)
b(Derv)


Is a function overload of a base class really ranked as "lower quality" than a function template? If so, is there an easy way to change this?



https://ideone.com/jD2lgz










share|improve this question



























    2















    The following code has a couple of regular function overloads, and - now - a template function intended as a catch-all if no overload is suitable.



    It almost works as I want, except that using derived classes (which previously ended up in the regular overload) get handled by the function template instead.



    #include <iostream>

    class Base { };
    class AnotherBase { };

    class Derv : public Base{ };

    class Derv2 : public Base { };

    class DervDerv : public Derv { };

    void f(const Base &b)
    {
    printf("b(Base)n");
    }

    void f(const Derv &b)
    {
    printf("b(Derv)n");
    }

    template<class T> void f(const T& t)
    {
    printf("b(template)n");
    }

    int main() {
    f(Base());
    f(AnotherBase());
    f(Derv());
    f(Derv2());
    f(DervDerv());

    return 0;
    }


    So the output I get is this...



    b(Base)
    b(template)
    b(Derv)
    b(template)
    b(template)


    ... when what I'd naively expected was this:



    b(Base)
    b(template)
    b(Derv)
    b(Base)
    b(Derv)


    Is a function overload of a base class really ranked as "lower quality" than a function template? If so, is there an easy way to change this?



    https://ideone.com/jD2lgz










    share|improve this question

























      2












      2








      2








      The following code has a couple of regular function overloads, and - now - a template function intended as a catch-all if no overload is suitable.



      It almost works as I want, except that using derived classes (which previously ended up in the regular overload) get handled by the function template instead.



      #include <iostream>

      class Base { };
      class AnotherBase { };

      class Derv : public Base{ };

      class Derv2 : public Base { };

      class DervDerv : public Derv { };

      void f(const Base &b)
      {
      printf("b(Base)n");
      }

      void f(const Derv &b)
      {
      printf("b(Derv)n");
      }

      template<class T> void f(const T& t)
      {
      printf("b(template)n");
      }

      int main() {
      f(Base());
      f(AnotherBase());
      f(Derv());
      f(Derv2());
      f(DervDerv());

      return 0;
      }


      So the output I get is this...



      b(Base)
      b(template)
      b(Derv)
      b(template)
      b(template)


      ... when what I'd naively expected was this:



      b(Base)
      b(template)
      b(Derv)
      b(Base)
      b(Derv)


      Is a function overload of a base class really ranked as "lower quality" than a function template? If so, is there an easy way to change this?



      https://ideone.com/jD2lgz










      share|improve this question














      The following code has a couple of regular function overloads, and - now - a template function intended as a catch-all if no overload is suitable.



      It almost works as I want, except that using derived classes (which previously ended up in the regular overload) get handled by the function template instead.



      #include <iostream>

      class Base { };
      class AnotherBase { };

      class Derv : public Base{ };

      class Derv2 : public Base { };

      class DervDerv : public Derv { };

      void f(const Base &b)
      {
      printf("b(Base)n");
      }

      void f(const Derv &b)
      {
      printf("b(Derv)n");
      }

      template<class T> void f(const T& t)
      {
      printf("b(template)n");
      }

      int main() {
      f(Base());
      f(AnotherBase());
      f(Derv());
      f(Derv2());
      f(DervDerv());

      return 0;
      }


      So the output I get is this...



      b(Base)
      b(template)
      b(Derv)
      b(template)
      b(template)


      ... when what I'd naively expected was this:



      b(Base)
      b(template)
      b(Derv)
      b(Base)
      b(Derv)


      Is a function overload of a base class really ranked as "lower quality" than a function template? If so, is there an easy way to change this?



      https://ideone.com/jD2lgz







      c++ overload-resolution function-templates






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Dec 30 '18 at 12:08









      RoddyRoddy

      45.8k35146239




      45.8k35146239
























          1 Answer
          1






          active

          oldest

          votes


















          3














          It's not about "quality". It's about conversions, just like it is with any other overload. To do overload resolution on the call to f(Derv2());, a compiler will synthesize a declaration like this one from your function template:



          void f(const Derv2& t);


          Which it pits against the other declared overloads. This overload gets picked for the exact same reason f(const Derv &) is a better match than f(const Base &) when you write f(Derv());.



          A "catch-all" template will do just that, it will catch everything for which there isn't an exact user-defined overload. If you want to prevent that, you need to constrain the template with meta programming. A simple trick that relies on SFINAE would look like this:



          template<class T>
          auto f(const T& t) -> std::enable_if_t<!std::is_convertible<T*, Base*>::value>
          {
          printf("b(template)n");
          }


          That produces the exact output you expected. Though obviously, you'd need to know what to constrain against in advance.






          share|improve this answer


























          • Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?

            – Roddy
            Dec 30 '18 at 12:38













          • @Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.

            – StoryTeller
            Dec 30 '18 at 12:39













          • As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As is std::is_convertible<T*, Base*>::value, which can be used instead of is_base_of. Look those up.

            – StoryTeller
            Dec 30 '18 at 12:41













          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%2f53977457%2ffunction-template-and-regular-overloads%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          3














          It's not about "quality". It's about conversions, just like it is with any other overload. To do overload resolution on the call to f(Derv2());, a compiler will synthesize a declaration like this one from your function template:



          void f(const Derv2& t);


          Which it pits against the other declared overloads. This overload gets picked for the exact same reason f(const Derv &) is a better match than f(const Base &) when you write f(Derv());.



          A "catch-all" template will do just that, it will catch everything for which there isn't an exact user-defined overload. If you want to prevent that, you need to constrain the template with meta programming. A simple trick that relies on SFINAE would look like this:



          template<class T>
          auto f(const T& t) -> std::enable_if_t<!std::is_convertible<T*, Base*>::value>
          {
          printf("b(template)n");
          }


          That produces the exact output you expected. Though obviously, you'd need to know what to constrain against in advance.






          share|improve this answer


























          • Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?

            – Roddy
            Dec 30 '18 at 12:38













          • @Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.

            – StoryTeller
            Dec 30 '18 at 12:39













          • As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As is std::is_convertible<T*, Base*>::value, which can be used instead of is_base_of. Look those up.

            – StoryTeller
            Dec 30 '18 at 12:41


















          3














          It's not about "quality". It's about conversions, just like it is with any other overload. To do overload resolution on the call to f(Derv2());, a compiler will synthesize a declaration like this one from your function template:



          void f(const Derv2& t);


          Which it pits against the other declared overloads. This overload gets picked for the exact same reason f(const Derv &) is a better match than f(const Base &) when you write f(Derv());.



          A "catch-all" template will do just that, it will catch everything for which there isn't an exact user-defined overload. If you want to prevent that, you need to constrain the template with meta programming. A simple trick that relies on SFINAE would look like this:



          template<class T>
          auto f(const T& t) -> std::enable_if_t<!std::is_convertible<T*, Base*>::value>
          {
          printf("b(template)n");
          }


          That produces the exact output you expected. Though obviously, you'd need to know what to constrain against in advance.






          share|improve this answer


























          • Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?

            – Roddy
            Dec 30 '18 at 12:38













          • @Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.

            – StoryTeller
            Dec 30 '18 at 12:39













          • As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As is std::is_convertible<T*, Base*>::value, which can be used instead of is_base_of. Look those up.

            – StoryTeller
            Dec 30 '18 at 12:41
















          3












          3








          3







          It's not about "quality". It's about conversions, just like it is with any other overload. To do overload resolution on the call to f(Derv2());, a compiler will synthesize a declaration like this one from your function template:



          void f(const Derv2& t);


          Which it pits against the other declared overloads. This overload gets picked for the exact same reason f(const Derv &) is a better match than f(const Base &) when you write f(Derv());.



          A "catch-all" template will do just that, it will catch everything for which there isn't an exact user-defined overload. If you want to prevent that, you need to constrain the template with meta programming. A simple trick that relies on SFINAE would look like this:



          template<class T>
          auto f(const T& t) -> std::enable_if_t<!std::is_convertible<T*, Base*>::value>
          {
          printf("b(template)n");
          }


          That produces the exact output you expected. Though obviously, you'd need to know what to constrain against in advance.






          share|improve this answer















          It's not about "quality". It's about conversions, just like it is with any other overload. To do overload resolution on the call to f(Derv2());, a compiler will synthesize a declaration like this one from your function template:



          void f(const Derv2& t);


          Which it pits against the other declared overloads. This overload gets picked for the exact same reason f(const Derv &) is a better match than f(const Base &) when you write f(Derv());.



          A "catch-all" template will do just that, it will catch everything for which there isn't an exact user-defined overload. If you want to prevent that, you need to constrain the template with meta programming. A simple trick that relies on SFINAE would look like this:



          template<class T>
          auto f(const T& t) -> std::enable_if_t<!std::is_convertible<T*, Base*>::value>
          {
          printf("b(template)n");
          }


          That produces the exact output you expected. Though obviously, you'd need to know what to constrain against in advance.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Dec 30 '18 at 12:47

























          answered Dec 30 '18 at 12:21









          StoryTellerStoryTeller

          97.1k12198264




          97.1k12198264













          • Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?

            – Roddy
            Dec 30 '18 at 12:38













          • @Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.

            – StoryTeller
            Dec 30 '18 at 12:39













          • As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As is std::is_convertible<T*, Base*>::value, which can be used instead of is_base_of. Look those up.

            – StoryTeller
            Dec 30 '18 at 12:41





















          • Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?

            – Roddy
            Dec 30 '18 at 12:38













          • @Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.

            – StoryTeller
            Dec 30 '18 at 12:39













          • As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As is std::is_convertible<T*, Base*>::value, which can be used instead of is_base_of. Look those up.

            – StoryTeller
            Dec 30 '18 at 12:41



















          Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?

          – Roddy
          Dec 30 '18 at 12:38







          Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?

          – Roddy
          Dec 30 '18 at 12:38















          @Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.

          – StoryTeller
          Dec 30 '18 at 12:39







          @Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.

          – StoryTeller
          Dec 30 '18 at 12:39















          As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As is std::is_convertible<T*, Base*>::value, which can be used instead of is_base_of. Look those up.

          – StoryTeller
          Dec 30 '18 at 12:41







          As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As is std::is_convertible<T*, Base*>::value, which can be used instead of is_base_of. Look those up.

          – StoryTeller
          Dec 30 '18 at 12:41




















          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%2f53977457%2ffunction-template-and-regular-overloads%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







          5h,DfUppuPUuwuTTJ,c31 pDoe4VOX0zsJG c1rZTTwA1 bYIHBd3562IshjRwG4QiZU8uu1QiXJznj,ERgYddNp
          sQn2s9MEN,hwwV lsgTj,uo63Me,udSPD70TbEAL8tqNzjFVfkcdmpF8,tTt,8 DIC6AuR6C gvT6oE,kYOTdSMWLoR6,5I

          Popular posts from this blog

          Monofisismo

          Angular Downloading a file using contenturl with Basic Authentication

          Olmecas