Trying to specialize a template function based on the presence of a typedef within class











up vote
0
down vote

favorite












I want to be able to customize handling of a struct based on the presence of a type within the struct (without writing any additional code per custom struct), like:



struct Normal_t
{
};

struct Custom_t
{
using my_custom_type = bool;
};


It seems like I should be able to do something like this, but it doesn't work:



template <class T, typename Enabler = void>
struct has_custom_type
{
bool operator()() { return false; }
};

template <class T>
struct has_custom_type<T, typename T::my_custom_type>
{
bool operator()() { return true; }
};

bool b_normal = has_custom_type<Normal_t>()(); // returns false
bool b_custom = has_custom_type<Custom_t>()(); // returns false, INCORRECT? should return true?


What I don't understand is that the standard library uses something similar but seemingly more convoluted for its type traits. For example, this works:



template<bool test, class T = void>
struct my_enable_if
{
};

template<class T>
struct my_enable_if<true, T>
{
using type = T;
};

template <class T, class Enabler = void>
struct foo
{
bool operator()() { return false; }
};

template <class T>
struct foo<T, typename my_enable_if<std::is_integral<T>::value>::type>
{
bool operator()() { return true; }
};

bool foo_float = foo<float>()(); // returns false
bool foo_int = foo<int>()(); // returns true


In both cases, the specialization is happening based on the presence of a type within a struct, in one case typename T::my_custom_type and in the other typename my_enable_if<std::is_integral<T>::value>::type. Why does the second version work but not the first?



I came up with this workaround using the ... parameter pack syntax, but I'd really like to understand if there is a way to do this using normal template specialization without using the parameter pack syntax, and if not, why.



template<typename ...Args>                              
bool has_custom_type_2(Args&& ...args) { return false; }

template<class T, std::size_t = sizeof(T::my_custom_type)>
bool has_custom_type_2(T&) { return true; }

template<class T, std::size_t = sizeof(T::my_custom_type)>
bool has_custom_type_2(T&&) { return true; } /* Need this T&& version to handle has_custom_type_2(SomeClass()) where the parameter is an rvalue */

bool b2_normal = has_custom_type_2(Normal_t()); // returns false
bool b2_custom = has_custom_type_2(Custom_t()); // returns true - CORRECT!









share|improve this question




























    up vote
    0
    down vote

    favorite












    I want to be able to customize handling of a struct based on the presence of a type within the struct (without writing any additional code per custom struct), like:



    struct Normal_t
    {
    };

    struct Custom_t
    {
    using my_custom_type = bool;
    };


    It seems like I should be able to do something like this, but it doesn't work:



    template <class T, typename Enabler = void>
    struct has_custom_type
    {
    bool operator()() { return false; }
    };

    template <class T>
    struct has_custom_type<T, typename T::my_custom_type>
    {
    bool operator()() { return true; }
    };

    bool b_normal = has_custom_type<Normal_t>()(); // returns false
    bool b_custom = has_custom_type<Custom_t>()(); // returns false, INCORRECT? should return true?


    What I don't understand is that the standard library uses something similar but seemingly more convoluted for its type traits. For example, this works:



    template<bool test, class T = void>
    struct my_enable_if
    {
    };

    template<class T>
    struct my_enable_if<true, T>
    {
    using type = T;
    };

    template <class T, class Enabler = void>
    struct foo
    {
    bool operator()() { return false; }
    };

    template <class T>
    struct foo<T, typename my_enable_if<std::is_integral<T>::value>::type>
    {
    bool operator()() { return true; }
    };

    bool foo_float = foo<float>()(); // returns false
    bool foo_int = foo<int>()(); // returns true


    In both cases, the specialization is happening based on the presence of a type within a struct, in one case typename T::my_custom_type and in the other typename my_enable_if<std::is_integral<T>::value>::type. Why does the second version work but not the first?



    I came up with this workaround using the ... parameter pack syntax, but I'd really like to understand if there is a way to do this using normal template specialization without using the parameter pack syntax, and if not, why.



    template<typename ...Args>                              
    bool has_custom_type_2(Args&& ...args) { return false; }

    template<class T, std::size_t = sizeof(T::my_custom_type)>
    bool has_custom_type_2(T&) { return true; }

    template<class T, std::size_t = sizeof(T::my_custom_type)>
    bool has_custom_type_2(T&&) { return true; } /* Need this T&& version to handle has_custom_type_2(SomeClass()) where the parameter is an rvalue */

    bool b2_normal = has_custom_type_2(Normal_t()); // returns false
    bool b2_custom = has_custom_type_2(Custom_t()); // returns true - CORRECT!









    share|improve this question


























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I want to be able to customize handling of a struct based on the presence of a type within the struct (without writing any additional code per custom struct), like:



      struct Normal_t
      {
      };

      struct Custom_t
      {
      using my_custom_type = bool;
      };


      It seems like I should be able to do something like this, but it doesn't work:



      template <class T, typename Enabler = void>
      struct has_custom_type
      {
      bool operator()() { return false; }
      };

      template <class T>
      struct has_custom_type<T, typename T::my_custom_type>
      {
      bool operator()() { return true; }
      };

      bool b_normal = has_custom_type<Normal_t>()(); // returns false
      bool b_custom = has_custom_type<Custom_t>()(); // returns false, INCORRECT? should return true?


      What I don't understand is that the standard library uses something similar but seemingly more convoluted for its type traits. For example, this works:



      template<bool test, class T = void>
      struct my_enable_if
      {
      };

      template<class T>
      struct my_enable_if<true, T>
      {
      using type = T;
      };

      template <class T, class Enabler = void>
      struct foo
      {
      bool operator()() { return false; }
      };

      template <class T>
      struct foo<T, typename my_enable_if<std::is_integral<T>::value>::type>
      {
      bool operator()() { return true; }
      };

      bool foo_float = foo<float>()(); // returns false
      bool foo_int = foo<int>()(); // returns true


      In both cases, the specialization is happening based on the presence of a type within a struct, in one case typename T::my_custom_type and in the other typename my_enable_if<std::is_integral<T>::value>::type. Why does the second version work but not the first?



      I came up with this workaround using the ... parameter pack syntax, but I'd really like to understand if there is a way to do this using normal template specialization without using the parameter pack syntax, and if not, why.



      template<typename ...Args>                              
      bool has_custom_type_2(Args&& ...args) { return false; }

      template<class T, std::size_t = sizeof(T::my_custom_type)>
      bool has_custom_type_2(T&) { return true; }

      template<class T, std::size_t = sizeof(T::my_custom_type)>
      bool has_custom_type_2(T&&) { return true; } /* Need this T&& version to handle has_custom_type_2(SomeClass()) where the parameter is an rvalue */

      bool b2_normal = has_custom_type_2(Normal_t()); // returns false
      bool b2_custom = has_custom_type_2(Custom_t()); // returns true - CORRECT!









      share|improve this question















      I want to be able to customize handling of a struct based on the presence of a type within the struct (without writing any additional code per custom struct), like:



      struct Normal_t
      {
      };

      struct Custom_t
      {
      using my_custom_type = bool;
      };


      It seems like I should be able to do something like this, but it doesn't work:



      template <class T, typename Enabler = void>
      struct has_custom_type
      {
      bool operator()() { return false; }
      };

      template <class T>
      struct has_custom_type<T, typename T::my_custom_type>
      {
      bool operator()() { return true; }
      };

      bool b_normal = has_custom_type<Normal_t>()(); // returns false
      bool b_custom = has_custom_type<Custom_t>()(); // returns false, INCORRECT? should return true?


      What I don't understand is that the standard library uses something similar but seemingly more convoluted for its type traits. For example, this works:



      template<bool test, class T = void>
      struct my_enable_if
      {
      };

      template<class T>
      struct my_enable_if<true, T>
      {
      using type = T;
      };

      template <class T, class Enabler = void>
      struct foo
      {
      bool operator()() { return false; }
      };

      template <class T>
      struct foo<T, typename my_enable_if<std::is_integral<T>::value>::type>
      {
      bool operator()() { return true; }
      };

      bool foo_float = foo<float>()(); // returns false
      bool foo_int = foo<int>()(); // returns true


      In both cases, the specialization is happening based on the presence of a type within a struct, in one case typename T::my_custom_type and in the other typename my_enable_if<std::is_integral<T>::value>::type. Why does the second version work but not the first?



      I came up with this workaround using the ... parameter pack syntax, but I'd really like to understand if there is a way to do this using normal template specialization without using the parameter pack syntax, and if not, why.



      template<typename ...Args>                              
      bool has_custom_type_2(Args&& ...args) { return false; }

      template<class T, std::size_t = sizeof(T::my_custom_type)>
      bool has_custom_type_2(T&) { return true; }

      template<class T, std::size_t = sizeof(T::my_custom_type)>
      bool has_custom_type_2(T&&) { return true; } /* Need this T&& version to handle has_custom_type_2(SomeClass()) where the parameter is an rvalue */

      bool b2_normal = has_custom_type_2(Normal_t()); // returns false
      bool b2_custom = has_custom_type_2(Custom_t()); // returns true - CORRECT!






      c++ templates variadic-templates sfinae template-specialization






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 10 at 19:23









      max66

      33.1k63660




      33.1k63660










      asked Oct 24 at 19:37









      James Thrush

      564




      564
























          3 Answers
          3






          active

          oldest

          votes

















          up vote
          2
          down vote



          accepted










          The problem is that you specify default void type for Enabler, but T::my_custom_type is not void. Either use bool as default type, or use std::void_t that always returns void:



          template <class T, typename = void>
          struct has_custom_type : std::false_type { };

          template <class T>
          struct has_custom_type<T, std::void_t<typename T::my_custom_type>> : std::true_type { };


          This answer explains why types should match.






          share|improve this answer



















          • 1




            Thank you! That is exactly what I wanted. Changing that default type was the one thing I hadn't tried. Thank you also for pointing out std::void_t and the use of std::true_type/false_type. I think I now understand why the types need to match: when the template is instantiated by has_custom_type<Custom_t>, the compiler first only looks at the base template and says "ok, the template parameters are set to <Custom_t,void>", and only after that does it look for specializations that match and are more specific.
            – James Thrush
            Oct 25 at 7:20








          • 1




            @JamesThrush, exactly.
            – Evg
            Oct 25 at 8:25


















          up vote
          2
          down vote













          As explained by others, if you set a void default value for the second template parameter, your solution works only if my_custom_type is void.



          If my_custom_type is bool, you can set bool the default value. But isn't a great solution because loose generality.



          To be more general, you can use SFINAE through something that fail if my_custom_type doesn't exist but return ever the same type (void, usually) if my_custom_type is present.



          Pre C++17 you can use decltype(), std::declval and the power of comma operator



          template <class T, typename Enabler = void>
          struct has_custom_type
          { bool operator()() { return false; } };

          template <class T>
          struct has_custom_type<T,
          decltype( std::declval<typename T::my_custom_type>(), void() )>
          { bool operator()() { return true; } };


          Starting from C++17 it's simpler because you can use std::void_t (see Evg's answer, also for the use of std::true_type and std::false_type instead of defining an operator()).






          share|improve this answer






























            up vote
            1
            down vote













            template <class T, typename Enabler = void> // <== void set as default template parameter type
            struct has_custom_type
            {
            bool operator()() { return false; }
            };

            template <class T>
            struct has_custom_type<T, typename T::my_custom_type>
            {
            bool operator()() { return true; }
            };


            The specialization matches when it gets the template parameters <T, bool>. However, when you just specify <T>, without a second type, then it goes to the default type you specified =void to come up with the call <T, void>, which doesn't match your bool specialization.



            Live example showing it matches with explicit <T, bool>: https://godbolt.org/z/MEJvwT






            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%2f52976727%2ftrying-to-specialize-a-template-function-based-on-the-presence-of-a-typedef-with%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              3 Answers
              3






              active

              oldest

              votes








              3 Answers
              3






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes








              up vote
              2
              down vote



              accepted










              The problem is that you specify default void type for Enabler, but T::my_custom_type is not void. Either use bool as default type, or use std::void_t that always returns void:



              template <class T, typename = void>
              struct has_custom_type : std::false_type { };

              template <class T>
              struct has_custom_type<T, std::void_t<typename T::my_custom_type>> : std::true_type { };


              This answer explains why types should match.






              share|improve this answer



















              • 1




                Thank you! That is exactly what I wanted. Changing that default type was the one thing I hadn't tried. Thank you also for pointing out std::void_t and the use of std::true_type/false_type. I think I now understand why the types need to match: when the template is instantiated by has_custom_type<Custom_t>, the compiler first only looks at the base template and says "ok, the template parameters are set to <Custom_t,void>", and only after that does it look for specializations that match and are more specific.
                – James Thrush
                Oct 25 at 7:20








              • 1




                @JamesThrush, exactly.
                – Evg
                Oct 25 at 8:25















              up vote
              2
              down vote



              accepted










              The problem is that you specify default void type for Enabler, but T::my_custom_type is not void. Either use bool as default type, or use std::void_t that always returns void:



              template <class T, typename = void>
              struct has_custom_type : std::false_type { };

              template <class T>
              struct has_custom_type<T, std::void_t<typename T::my_custom_type>> : std::true_type { };


              This answer explains why types should match.






              share|improve this answer



















              • 1




                Thank you! That is exactly what I wanted. Changing that default type was the one thing I hadn't tried. Thank you also for pointing out std::void_t and the use of std::true_type/false_type. I think I now understand why the types need to match: when the template is instantiated by has_custom_type<Custom_t>, the compiler first only looks at the base template and says "ok, the template parameters are set to <Custom_t,void>", and only after that does it look for specializations that match and are more specific.
                – James Thrush
                Oct 25 at 7:20








              • 1




                @JamesThrush, exactly.
                – Evg
                Oct 25 at 8:25













              up vote
              2
              down vote



              accepted







              up vote
              2
              down vote



              accepted






              The problem is that you specify default void type for Enabler, but T::my_custom_type is not void. Either use bool as default type, or use std::void_t that always returns void:



              template <class T, typename = void>
              struct has_custom_type : std::false_type { };

              template <class T>
              struct has_custom_type<T, std::void_t<typename T::my_custom_type>> : std::true_type { };


              This answer explains why types should match.






              share|improve this answer














              The problem is that you specify default void type for Enabler, but T::my_custom_type is not void. Either use bool as default type, or use std::void_t that always returns void:



              template <class T, typename = void>
              struct has_custom_type : std::false_type { };

              template <class T>
              struct has_custom_type<T, std::void_t<typename T::my_custom_type>> : std::true_type { };


              This answer explains why types should match.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Oct 24 at 20:02

























              answered Oct 24 at 19:46









              Evg

              3,74221334




              3,74221334








              • 1




                Thank you! That is exactly what I wanted. Changing that default type was the one thing I hadn't tried. Thank you also for pointing out std::void_t and the use of std::true_type/false_type. I think I now understand why the types need to match: when the template is instantiated by has_custom_type<Custom_t>, the compiler first only looks at the base template and says "ok, the template parameters are set to <Custom_t,void>", and only after that does it look for specializations that match and are more specific.
                – James Thrush
                Oct 25 at 7:20








              • 1




                @JamesThrush, exactly.
                – Evg
                Oct 25 at 8:25














              • 1




                Thank you! That is exactly what I wanted. Changing that default type was the one thing I hadn't tried. Thank you also for pointing out std::void_t and the use of std::true_type/false_type. I think I now understand why the types need to match: when the template is instantiated by has_custom_type<Custom_t>, the compiler first only looks at the base template and says "ok, the template parameters are set to <Custom_t,void>", and only after that does it look for specializations that match and are more specific.
                – James Thrush
                Oct 25 at 7:20








              • 1




                @JamesThrush, exactly.
                – Evg
                Oct 25 at 8:25








              1




              1




              Thank you! That is exactly what I wanted. Changing that default type was the one thing I hadn't tried. Thank you also for pointing out std::void_t and the use of std::true_type/false_type. I think I now understand why the types need to match: when the template is instantiated by has_custom_type<Custom_t>, the compiler first only looks at the base template and says "ok, the template parameters are set to <Custom_t,void>", and only after that does it look for specializations that match and are more specific.
              – James Thrush
              Oct 25 at 7:20






              Thank you! That is exactly what I wanted. Changing that default type was the one thing I hadn't tried. Thank you also for pointing out std::void_t and the use of std::true_type/false_type. I think I now understand why the types need to match: when the template is instantiated by has_custom_type<Custom_t>, the compiler first only looks at the base template and says "ok, the template parameters are set to <Custom_t,void>", and only after that does it look for specializations that match and are more specific.
              – James Thrush
              Oct 25 at 7:20






              1




              1




              @JamesThrush, exactly.
              – Evg
              Oct 25 at 8:25




              @JamesThrush, exactly.
              – Evg
              Oct 25 at 8:25












              up vote
              2
              down vote













              As explained by others, if you set a void default value for the second template parameter, your solution works only if my_custom_type is void.



              If my_custom_type is bool, you can set bool the default value. But isn't a great solution because loose generality.



              To be more general, you can use SFINAE through something that fail if my_custom_type doesn't exist but return ever the same type (void, usually) if my_custom_type is present.



              Pre C++17 you can use decltype(), std::declval and the power of comma operator



              template <class T, typename Enabler = void>
              struct has_custom_type
              { bool operator()() { return false; } };

              template <class T>
              struct has_custom_type<T,
              decltype( std::declval<typename T::my_custom_type>(), void() )>
              { bool operator()() { return true; } };


              Starting from C++17 it's simpler because you can use std::void_t (see Evg's answer, also for the use of std::true_type and std::false_type instead of defining an operator()).






              share|improve this answer



























                up vote
                2
                down vote













                As explained by others, if you set a void default value for the second template parameter, your solution works only if my_custom_type is void.



                If my_custom_type is bool, you can set bool the default value. But isn't a great solution because loose generality.



                To be more general, you can use SFINAE through something that fail if my_custom_type doesn't exist but return ever the same type (void, usually) if my_custom_type is present.



                Pre C++17 you can use decltype(), std::declval and the power of comma operator



                template <class T, typename Enabler = void>
                struct has_custom_type
                { bool operator()() { return false; } };

                template <class T>
                struct has_custom_type<T,
                decltype( std::declval<typename T::my_custom_type>(), void() )>
                { bool operator()() { return true; } };


                Starting from C++17 it's simpler because you can use std::void_t (see Evg's answer, also for the use of std::true_type and std::false_type instead of defining an operator()).






                share|improve this answer

























                  up vote
                  2
                  down vote










                  up vote
                  2
                  down vote









                  As explained by others, if you set a void default value for the second template parameter, your solution works only if my_custom_type is void.



                  If my_custom_type is bool, you can set bool the default value. But isn't a great solution because loose generality.



                  To be more general, you can use SFINAE through something that fail if my_custom_type doesn't exist but return ever the same type (void, usually) if my_custom_type is present.



                  Pre C++17 you can use decltype(), std::declval and the power of comma operator



                  template <class T, typename Enabler = void>
                  struct has_custom_type
                  { bool operator()() { return false; } };

                  template <class T>
                  struct has_custom_type<T,
                  decltype( std::declval<typename T::my_custom_type>(), void() )>
                  { bool operator()() { return true; } };


                  Starting from C++17 it's simpler because you can use std::void_t (see Evg's answer, also for the use of std::true_type and std::false_type instead of defining an operator()).






                  share|improve this answer














                  As explained by others, if you set a void default value for the second template parameter, your solution works only if my_custom_type is void.



                  If my_custom_type is bool, you can set bool the default value. But isn't a great solution because loose generality.



                  To be more general, you can use SFINAE through something that fail if my_custom_type doesn't exist but return ever the same type (void, usually) if my_custom_type is present.



                  Pre C++17 you can use decltype(), std::declval and the power of comma operator



                  template <class T, typename Enabler = void>
                  struct has_custom_type
                  { bool operator()() { return false; } };

                  template <class T>
                  struct has_custom_type<T,
                  decltype( std::declval<typename T::my_custom_type>(), void() )>
                  { bool operator()() { return true; } };


                  Starting from C++17 it's simpler because you can use std::void_t (see Evg's answer, also for the use of std::true_type and std::false_type instead of defining an operator()).







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Oct 24 at 19:57

























                  answered Oct 24 at 19:51









                  max66

                  33.1k63660




                  33.1k63660






















                      up vote
                      1
                      down vote













                      template <class T, typename Enabler = void> // <== void set as default template parameter type
                      struct has_custom_type
                      {
                      bool operator()() { return false; }
                      };

                      template <class T>
                      struct has_custom_type<T, typename T::my_custom_type>
                      {
                      bool operator()() { return true; }
                      };


                      The specialization matches when it gets the template parameters <T, bool>. However, when you just specify <T>, without a second type, then it goes to the default type you specified =void to come up with the call <T, void>, which doesn't match your bool specialization.



                      Live example showing it matches with explicit <T, bool>: https://godbolt.org/z/MEJvwT






                      share|improve this answer

























                        up vote
                        1
                        down vote













                        template <class T, typename Enabler = void> // <== void set as default template parameter type
                        struct has_custom_type
                        {
                        bool operator()() { return false; }
                        };

                        template <class T>
                        struct has_custom_type<T, typename T::my_custom_type>
                        {
                        bool operator()() { return true; }
                        };


                        The specialization matches when it gets the template parameters <T, bool>. However, when you just specify <T>, without a second type, then it goes to the default type you specified =void to come up with the call <T, void>, which doesn't match your bool specialization.



                        Live example showing it matches with explicit <T, bool>: https://godbolt.org/z/MEJvwT






                        share|improve this answer























                          up vote
                          1
                          down vote










                          up vote
                          1
                          down vote









                          template <class T, typename Enabler = void> // <== void set as default template parameter type
                          struct has_custom_type
                          {
                          bool operator()() { return false; }
                          };

                          template <class T>
                          struct has_custom_type<T, typename T::my_custom_type>
                          {
                          bool operator()() { return true; }
                          };


                          The specialization matches when it gets the template parameters <T, bool>. However, when you just specify <T>, without a second type, then it goes to the default type you specified =void to come up with the call <T, void>, which doesn't match your bool specialization.



                          Live example showing it matches with explicit <T, bool>: https://godbolt.org/z/MEJvwT






                          share|improve this answer












                          template <class T, typename Enabler = void> // <== void set as default template parameter type
                          struct has_custom_type
                          {
                          bool operator()() { return false; }
                          };

                          template <class T>
                          struct has_custom_type<T, typename T::my_custom_type>
                          {
                          bool operator()() { return true; }
                          };


                          The specialization matches when it gets the template parameters <T, bool>. However, when you just specify <T>, without a second type, then it goes to the default type you specified =void to come up with the call <T, void>, which doesn't match your bool specialization.



                          Live example showing it matches with explicit <T, bool>: https://godbolt.org/z/MEJvwT







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Oct 24 at 19:49









                          xaxxon

                          14.3k43058




                          14.3k43058






























                              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.





                              Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                              Please pay close attention to the following guidance:


                              • 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%2f52976727%2ftrying-to-specialize-a-template-function-based-on-the-presence-of-a-typedef-with%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

                              Guess what letter conforming each word

                              Port of Spain

                              Run scheduled task as local user group (not BUILTIN)