Declaring and defining template, and specialising them












7















I'm trying to understand the below example, but I'm a bit confused from the three different template and struct declarations.



Could you please describe what will happen for the below call? which of the templates will be used and when?



Also why does the first template+class declaration is lacking "<S...>" right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?



#include <iostream>
#include <stdio.h>
using namespace std;


template<typename... S>
struct Example /* <S...> */ ;

template<typename H, typename... T>
struct Example<H, T...>
{
static const size_t value = sizeof(H) + Example<T...>::value;
};

template<>
struct Example<>
{
static const size_t value = 0;
};


int main(){
cout << Example<long, int, char>::value << endl;
return 0;
}


Output: 13










share|improve this question









New contributor




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

























    7















    I'm trying to understand the below example, but I'm a bit confused from the three different template and struct declarations.



    Could you please describe what will happen for the below call? which of the templates will be used and when?



    Also why does the first template+class declaration is lacking "<S...>" right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?



    #include <iostream>
    #include <stdio.h>
    using namespace std;


    template<typename... S>
    struct Example /* <S...> */ ;

    template<typename H, typename... T>
    struct Example<H, T...>
    {
    static const size_t value = sizeof(H) + Example<T...>::value;
    };

    template<>
    struct Example<>
    {
    static const size_t value = 0;
    };


    int main(){
    cout << Example<long, int, char>::value << endl;
    return 0;
    }


    Output: 13










    share|improve this question









    New contributor




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























      7












      7








      7


      1






      I'm trying to understand the below example, but I'm a bit confused from the three different template and struct declarations.



      Could you please describe what will happen for the below call? which of the templates will be used and when?



      Also why does the first template+class declaration is lacking "<S...>" right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?



      #include <iostream>
      #include <stdio.h>
      using namespace std;


      template<typename... S>
      struct Example /* <S...> */ ;

      template<typename H, typename... T>
      struct Example<H, T...>
      {
      static const size_t value = sizeof(H) + Example<T...>::value;
      };

      template<>
      struct Example<>
      {
      static const size_t value = 0;
      };


      int main(){
      cout << Example<long, int, char>::value << endl;
      return 0;
      }


      Output: 13










      share|improve this question









      New contributor




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












      I'm trying to understand the below example, but I'm a bit confused from the three different template and struct declarations.



      Could you please describe what will happen for the below call? which of the templates will be used and when?



      Also why does the first template+class declaration is lacking "<S...>" right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?



      #include <iostream>
      #include <stdio.h>
      using namespace std;


      template<typename... S>
      struct Example /* <S...> */ ;

      template<typename H, typename... T>
      struct Example<H, T...>
      {
      static const size_t value = sizeof(H) + Example<T...>::value;
      };

      template<>
      struct Example<>
      {
      static const size_t value = 0;
      };


      int main(){
      cout << Example<long, int, char>::value << endl;
      return 0;
      }


      Output: 13







      c++ c++11 templates variadic-templates template-specialization






      share|improve this question









      New contributor




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











      share|improve this question









      New contributor




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









      share|improve this question




      share|improve this question








      edited 1 hour ago









      max66

      37.7k74370




      37.7k74370






      New contributor




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









      asked 2 hours ago









      katkatokatkato

      362




      362




      New contributor




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





      New contributor





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






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
























          3 Answers
          3






          active

          oldest

          votes


















          4














          The first declares the template of a struct named Example, accepting any number of types:



          template<typename... S>
          struct Example /* <S...> */ ;


          If the name of the newly declared template was followed by <>, with or without arguments, it would be a specialization instead!



          The second defines a partial specialization for at least one type-argument:



          template<typename H, typename... T>
          struct Example<H, T...>
          {
          static const size_t value = sizeof(H) + Example<T...>::value;
          };


          And the last one defines a full specialization for no type-arguments:



          template<>
          struct Example<>
          {
          static const size_t value = 0;
          };


          Take note that template is followed by empty <>-brackets.



          It doesn't matter that the partial specialization is defined before the full specialization because instantiation must be deferred until the templates type-arguments are known.



          The specific instance you use, Example<long,int,char>::value, depends on Example<int, char>::value, which depends on Example<char>, which leads to the base-case:



          Example<long, int, char>::value = sizeof(long) + Example<int, char>::value; // sizeof(long) + sizeof(int) + 1 + 0
          Example<int, char>::value = sizeof(int) + Example<char>::value; // sizeof(int) + 1 + 0
          Example<char>::value = sizeof(char) + Example<>::value; // 1 + 0
          Example<>::value = 0;


          Of course, the example could be simplified:



          template <class... T>
          struct Example {
          static const size_t value = 0;
          static_assert(!sizeof...(T), "The base-template only handles no template arguments.");
          };
          template <class H, class... T>
          struct Example {
          static const size_t value = sizeof(H) + Example<T...>::example;
          };


          Or with C++17 fold-expressions:



          template <class... T>
          struct Example {
          static const size_t value = 0 + ... + sizeof(T);
          };


          As an aside, there are good reasons never to use using namespace std;, I wonder why you #include <stdio.h>, and return 0; is redundant for main().






          share|improve this answer

































            3














            Only answering this part of your question:




            Also why does the first template+class declaration is lacking < S...> right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?






            • When you declare a templated function/class/struct/type, you only use the angle bracket< > once, before the declaration:



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



            • When you declare a specific instantiation of the general template, you use < > twice, once empty before the declaration, then again with the specific template parameters for which you're instantating:



              template <>
              void foo<int>(int& x);



            • When you declare a specific specialization of the general template, you use < > twice, once empty before the declaration, then again with the specific template parameters for which you're instantating:



              template 
              void foo<int>(int& x);



            More on the last two items (and how they differ):



            Difference between instantiation and specialization in c++ templates






            share|improve this answer

































              1















              Also why does the first template+class declaration is lacking "< S...>" right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?




              It seems to me that is better to start from this point.



              First of all, the following (removed the <S...> commented) is a declaration (attention: declaration only, not definition) of a template struct Example that receive a variadic list of type template parameters



              template<typename... S>
              struct Example;


              You can also avoid to use the S and write simply



              template <typename...>
              struct Example;


              because the name of the variadic list isn't used in this context.



              At this point the compiler know that there is a variadic template struct Example but doesn't know how is made.



              Next we add the definition of a specialization of Example that receive one or more template parameter (observe that Example is defined to receive zero or more parameter, so a specialization that receive one or more parameter is special case of Example)



              //....... one --> V          VVVVV <- or more template parameter
              template<typename H, typename... T>
              struct Example<H, T...>
              { // .........^^^^^^^^^ <- this is a specialization
              static const size_t value = sizeof(H) + Example<T...>::value;
              };


              The <H, T...> part after Example identifies a specialization (as said).



              This specialization define a static const size_t variable initialized with the sum of the sizeof(H) (the sizeof() of the first type template parameter) with the value defined in another Example class: Example<T...>.



              So you're observing a recursive definition: value is the sum of the sizeof() of the first parameter (a type) with the sum of the sizeof() of the following types.



              Suggestion: if you use variadic templates, you can use also constexpr, so better define value as constexpr



               static constexpr std::size_t value = sizeof(H) + Example<T...>::value;


              Or better, you can inherit from std::integral_constant



              template <typename H, typename... T>
              struct Example <H, T...>
              : public std::integral_constant<std::size_t, sizeof(H) + Example<T...>{}>
              { };


              so you inherit value from std::integral_constant with additional useful facilities (by example: automatic conversion to std::size_t in a context where a std::size_t is required)



              Every recursion needs a ground case, so you have



              template<>
              struct Example<>
              {
              static const size_t value = 0;
              };


              the declaration of another specialization of Example; this time the case with exactly zero template parameter (Example<>). In this case you have the definition of a value that is zero to terminate the recursion.



              As before, you can define value as constexpr or, better IMHO, using again std::integral_constant



              template <>
              struct Example<> : public std::integral_constant<std::size_t, 0u>
              { };


              Now you have defined two specializations for Example: one for the one-or-more parameters cases, one for the zero-parameters case. So you have covered all cases for Example that is declared receiving zero-or-more parameters; there is no needs to declare the generic (not specialized version) of Example.



              As observed by Deduplicator, you can define the generic case and only one specialization: if you write



              template <typename...>
              struct Example : public std::integral_constant<std::size_t, 0u>
              { };

              template <typename T, typename ... Ts>
              struct Example<T, Ts...>
              : public std::integral_constant<std::size_t, sizeof(T)+Example<Ts...>{}>
              { };


              you first declare Example receiving zero-or-more parameters and define the generic case with a value zero (the ground case), next you define a one-or-more specialization.



              Considering that the compiler select the more specialized version (when more version matches), the compiler select the specialization when there is one-or-more parameters (bot versions match but the specialization is more specialized) and the generic version when there are zero parameters (because the specialization doesn't matches).



              This way is a little more synthetic but can be less clear.




              Could you please describe what will happen for the below call? which of the templates will be used and when?




              Now should be simple to understand.



              When you write



              Example<long, int, char>::value


              you ask for the value of Example<long, int, char>.



              Three parameters, so the one-or-more specialization is selected, that is



              value = sizeof(long) + Example<int, char>::value;


              for the same reason, the value in Example<int, char> is



              value = sizeof(int) + Example<char>::value;


              and the value in Example<char> is



              value = sizeof(char) + Example<>::value;


              Now, for Example<>::value, the zero-parameters specialization is selected and Example<>::value is zero.



              Concluding, we have that value in Example<long, int, char> is initialized with



               value = sizeof(long) + sizeof(int) + sizeof(char) + 0;


              You tagged C++11, so it's a pity you can't use C++17 (template folding) where you can avoid recursion at all and define Example as a using



              template <typename ... Ts>
              using Example = std::integral_constant<std::size_t, (... + sizeof(Ts))>;





              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',
                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
                });


                }
                });






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










                draft saved

                draft discarded


















                StackExchange.ready(
                function () {
                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55109599%2fdeclaring-and-defining-template-and-specialising-them%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









                4














                The first declares the template of a struct named Example, accepting any number of types:



                template<typename... S>
                struct Example /* <S...> */ ;


                If the name of the newly declared template was followed by <>, with or without arguments, it would be a specialization instead!



                The second defines a partial specialization for at least one type-argument:



                template<typename H, typename... T>
                struct Example<H, T...>
                {
                static const size_t value = sizeof(H) + Example<T...>::value;
                };


                And the last one defines a full specialization for no type-arguments:



                template<>
                struct Example<>
                {
                static const size_t value = 0;
                };


                Take note that template is followed by empty <>-brackets.



                It doesn't matter that the partial specialization is defined before the full specialization because instantiation must be deferred until the templates type-arguments are known.



                The specific instance you use, Example<long,int,char>::value, depends on Example<int, char>::value, which depends on Example<char>, which leads to the base-case:



                Example<long, int, char>::value = sizeof(long) + Example<int, char>::value; // sizeof(long) + sizeof(int) + 1 + 0
                Example<int, char>::value = sizeof(int) + Example<char>::value; // sizeof(int) + 1 + 0
                Example<char>::value = sizeof(char) + Example<>::value; // 1 + 0
                Example<>::value = 0;


                Of course, the example could be simplified:



                template <class... T>
                struct Example {
                static const size_t value = 0;
                static_assert(!sizeof...(T), "The base-template only handles no template arguments.");
                };
                template <class H, class... T>
                struct Example {
                static const size_t value = sizeof(H) + Example<T...>::example;
                };


                Or with C++17 fold-expressions:



                template <class... T>
                struct Example {
                static const size_t value = 0 + ... + sizeof(T);
                };


                As an aside, there are good reasons never to use using namespace std;, I wonder why you #include <stdio.h>, and return 0; is redundant for main().






                share|improve this answer






























                  4














                  The first declares the template of a struct named Example, accepting any number of types:



                  template<typename... S>
                  struct Example /* <S...> */ ;


                  If the name of the newly declared template was followed by <>, with or without arguments, it would be a specialization instead!



                  The second defines a partial specialization for at least one type-argument:



                  template<typename H, typename... T>
                  struct Example<H, T...>
                  {
                  static const size_t value = sizeof(H) + Example<T...>::value;
                  };


                  And the last one defines a full specialization for no type-arguments:



                  template<>
                  struct Example<>
                  {
                  static const size_t value = 0;
                  };


                  Take note that template is followed by empty <>-brackets.



                  It doesn't matter that the partial specialization is defined before the full specialization because instantiation must be deferred until the templates type-arguments are known.



                  The specific instance you use, Example<long,int,char>::value, depends on Example<int, char>::value, which depends on Example<char>, which leads to the base-case:



                  Example<long, int, char>::value = sizeof(long) + Example<int, char>::value; // sizeof(long) + sizeof(int) + 1 + 0
                  Example<int, char>::value = sizeof(int) + Example<char>::value; // sizeof(int) + 1 + 0
                  Example<char>::value = sizeof(char) + Example<>::value; // 1 + 0
                  Example<>::value = 0;


                  Of course, the example could be simplified:



                  template <class... T>
                  struct Example {
                  static const size_t value = 0;
                  static_assert(!sizeof...(T), "The base-template only handles no template arguments.");
                  };
                  template <class H, class... T>
                  struct Example {
                  static const size_t value = sizeof(H) + Example<T...>::example;
                  };


                  Or with C++17 fold-expressions:



                  template <class... T>
                  struct Example {
                  static const size_t value = 0 + ... + sizeof(T);
                  };


                  As an aside, there are good reasons never to use using namespace std;, I wonder why you #include <stdio.h>, and return 0; is redundant for main().






                  share|improve this answer




























                    4












                    4








                    4







                    The first declares the template of a struct named Example, accepting any number of types:



                    template<typename... S>
                    struct Example /* <S...> */ ;


                    If the name of the newly declared template was followed by <>, with or without arguments, it would be a specialization instead!



                    The second defines a partial specialization for at least one type-argument:



                    template<typename H, typename... T>
                    struct Example<H, T...>
                    {
                    static const size_t value = sizeof(H) + Example<T...>::value;
                    };


                    And the last one defines a full specialization for no type-arguments:



                    template<>
                    struct Example<>
                    {
                    static const size_t value = 0;
                    };


                    Take note that template is followed by empty <>-brackets.



                    It doesn't matter that the partial specialization is defined before the full specialization because instantiation must be deferred until the templates type-arguments are known.



                    The specific instance you use, Example<long,int,char>::value, depends on Example<int, char>::value, which depends on Example<char>, which leads to the base-case:



                    Example<long, int, char>::value = sizeof(long) + Example<int, char>::value; // sizeof(long) + sizeof(int) + 1 + 0
                    Example<int, char>::value = sizeof(int) + Example<char>::value; // sizeof(int) + 1 + 0
                    Example<char>::value = sizeof(char) + Example<>::value; // 1 + 0
                    Example<>::value = 0;


                    Of course, the example could be simplified:



                    template <class... T>
                    struct Example {
                    static const size_t value = 0;
                    static_assert(!sizeof...(T), "The base-template only handles no template arguments.");
                    };
                    template <class H, class... T>
                    struct Example {
                    static const size_t value = sizeof(H) + Example<T...>::example;
                    };


                    Or with C++17 fold-expressions:



                    template <class... T>
                    struct Example {
                    static const size_t value = 0 + ... + sizeof(T);
                    };


                    As an aside, there are good reasons never to use using namespace std;, I wonder why you #include <stdio.h>, and return 0; is redundant for main().






                    share|improve this answer















                    The first declares the template of a struct named Example, accepting any number of types:



                    template<typename... S>
                    struct Example /* <S...> */ ;


                    If the name of the newly declared template was followed by <>, with or without arguments, it would be a specialization instead!



                    The second defines a partial specialization for at least one type-argument:



                    template<typename H, typename... T>
                    struct Example<H, T...>
                    {
                    static const size_t value = sizeof(H) + Example<T...>::value;
                    };


                    And the last one defines a full specialization for no type-arguments:



                    template<>
                    struct Example<>
                    {
                    static const size_t value = 0;
                    };


                    Take note that template is followed by empty <>-brackets.



                    It doesn't matter that the partial specialization is defined before the full specialization because instantiation must be deferred until the templates type-arguments are known.



                    The specific instance you use, Example<long,int,char>::value, depends on Example<int, char>::value, which depends on Example<char>, which leads to the base-case:



                    Example<long, int, char>::value = sizeof(long) + Example<int, char>::value; // sizeof(long) + sizeof(int) + 1 + 0
                    Example<int, char>::value = sizeof(int) + Example<char>::value; // sizeof(int) + 1 + 0
                    Example<char>::value = sizeof(char) + Example<>::value; // 1 + 0
                    Example<>::value = 0;


                    Of course, the example could be simplified:



                    template <class... T>
                    struct Example {
                    static const size_t value = 0;
                    static_assert(!sizeof...(T), "The base-template only handles no template arguments.");
                    };
                    template <class H, class... T>
                    struct Example {
                    static const size_t value = sizeof(H) + Example<T...>::example;
                    };


                    Or with C++17 fold-expressions:



                    template <class... T>
                    struct Example {
                    static const size_t value = 0 + ... + sizeof(T);
                    };


                    As an aside, there are good reasons never to use using namespace std;, I wonder why you #include <stdio.h>, and return 0; is redundant for main().







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited 1 hour ago









                    alter igel

                    2,76811027




                    2,76811027










                    answered 1 hour ago









                    DeduplicatorDeduplicator

                    34.7k64990




                    34.7k64990

























                        3














                        Only answering this part of your question:




                        Also why does the first template+class declaration is lacking < S...> right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?






                        • When you declare a templated function/class/struct/type, you only use the angle bracket< > once, before the declaration:



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



                        • When you declare a specific instantiation of the general template, you use < > twice, once empty before the declaration, then again with the specific template parameters for which you're instantating:



                          template <>
                          void foo<int>(int& x);



                        • When you declare a specific specialization of the general template, you use < > twice, once empty before the declaration, then again with the specific template parameters for which you're instantating:



                          template 
                          void foo<int>(int& x);



                        More on the last two items (and how they differ):



                        Difference between instantiation and specialization in c++ templates






                        share|improve this answer






























                          3














                          Only answering this part of your question:




                          Also why does the first template+class declaration is lacking < S...> right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?






                          • When you declare a templated function/class/struct/type, you only use the angle bracket< > once, before the declaration:



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



                          • When you declare a specific instantiation of the general template, you use < > twice, once empty before the declaration, then again with the specific template parameters for which you're instantating:



                            template <>
                            void foo<int>(int& x);



                          • When you declare a specific specialization of the general template, you use < > twice, once empty before the declaration, then again with the specific template parameters for which you're instantating:



                            template 
                            void foo<int>(int& x);



                          More on the last two items (and how they differ):



                          Difference between instantiation and specialization in c++ templates






                          share|improve this answer




























                            3












                            3








                            3







                            Only answering this part of your question:




                            Also why does the first template+class declaration is lacking < S...> right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?






                            • When you declare a templated function/class/struct/type, you only use the angle bracket< > once, before the declaration:



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



                            • When you declare a specific instantiation of the general template, you use < > twice, once empty before the declaration, then again with the specific template parameters for which you're instantating:



                              template <>
                              void foo<int>(int& x);



                            • When you declare a specific specialization of the general template, you use < > twice, once empty before the declaration, then again with the specific template parameters for which you're instantating:



                              template 
                              void foo<int>(int& x);



                            More on the last two items (and how they differ):



                            Difference between instantiation and specialization in c++ templates






                            share|improve this answer















                            Only answering this part of your question:




                            Also why does the first template+class declaration is lacking < S...> right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?






                            • When you declare a templated function/class/struct/type, you only use the angle bracket< > once, before the declaration:



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



                            • When you declare a specific instantiation of the general template, you use < > twice, once empty before the declaration, then again with the specific template parameters for which you're instantating:



                              template <>
                              void foo<int>(int& x);



                            • When you declare a specific specialization of the general template, you use < > twice, once empty before the declaration, then again with the specific template parameters for which you're instantating:



                              template 
                              void foo<int>(int& x);



                            More on the last two items (and how they differ):



                            Difference between instantiation and specialization in c++ templates







                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited 1 hour ago

























                            answered 1 hour ago









                            einpoklumeinpoklum

                            35.4k27129254




                            35.4k27129254























                                1















                                Also why does the first template+class declaration is lacking "< S...>" right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?




                                It seems to me that is better to start from this point.



                                First of all, the following (removed the <S...> commented) is a declaration (attention: declaration only, not definition) of a template struct Example that receive a variadic list of type template parameters



                                template<typename... S>
                                struct Example;


                                You can also avoid to use the S and write simply



                                template <typename...>
                                struct Example;


                                because the name of the variadic list isn't used in this context.



                                At this point the compiler know that there is a variadic template struct Example but doesn't know how is made.



                                Next we add the definition of a specialization of Example that receive one or more template parameter (observe that Example is defined to receive zero or more parameter, so a specialization that receive one or more parameter is special case of Example)



                                //....... one --> V          VVVVV <- or more template parameter
                                template<typename H, typename... T>
                                struct Example<H, T...>
                                { // .........^^^^^^^^^ <- this is a specialization
                                static const size_t value = sizeof(H) + Example<T...>::value;
                                };


                                The <H, T...> part after Example identifies a specialization (as said).



                                This specialization define a static const size_t variable initialized with the sum of the sizeof(H) (the sizeof() of the first type template parameter) with the value defined in another Example class: Example<T...>.



                                So you're observing a recursive definition: value is the sum of the sizeof() of the first parameter (a type) with the sum of the sizeof() of the following types.



                                Suggestion: if you use variadic templates, you can use also constexpr, so better define value as constexpr



                                 static constexpr std::size_t value = sizeof(H) + Example<T...>::value;


                                Or better, you can inherit from std::integral_constant



                                template <typename H, typename... T>
                                struct Example <H, T...>
                                : public std::integral_constant<std::size_t, sizeof(H) + Example<T...>{}>
                                { };


                                so you inherit value from std::integral_constant with additional useful facilities (by example: automatic conversion to std::size_t in a context where a std::size_t is required)



                                Every recursion needs a ground case, so you have



                                template<>
                                struct Example<>
                                {
                                static const size_t value = 0;
                                };


                                the declaration of another specialization of Example; this time the case with exactly zero template parameter (Example<>). In this case you have the definition of a value that is zero to terminate the recursion.



                                As before, you can define value as constexpr or, better IMHO, using again std::integral_constant



                                template <>
                                struct Example<> : public std::integral_constant<std::size_t, 0u>
                                { };


                                Now you have defined two specializations for Example: one for the one-or-more parameters cases, one for the zero-parameters case. So you have covered all cases for Example that is declared receiving zero-or-more parameters; there is no needs to declare the generic (not specialized version) of Example.



                                As observed by Deduplicator, you can define the generic case and only one specialization: if you write



                                template <typename...>
                                struct Example : public std::integral_constant<std::size_t, 0u>
                                { };

                                template <typename T, typename ... Ts>
                                struct Example<T, Ts...>
                                : public std::integral_constant<std::size_t, sizeof(T)+Example<Ts...>{}>
                                { };


                                you first declare Example receiving zero-or-more parameters and define the generic case with a value zero (the ground case), next you define a one-or-more specialization.



                                Considering that the compiler select the more specialized version (when more version matches), the compiler select the specialization when there is one-or-more parameters (bot versions match but the specialization is more specialized) and the generic version when there are zero parameters (because the specialization doesn't matches).



                                This way is a little more synthetic but can be less clear.




                                Could you please describe what will happen for the below call? which of the templates will be used and when?




                                Now should be simple to understand.



                                When you write



                                Example<long, int, char>::value


                                you ask for the value of Example<long, int, char>.



                                Three parameters, so the one-or-more specialization is selected, that is



                                value = sizeof(long) + Example<int, char>::value;


                                for the same reason, the value in Example<int, char> is



                                value = sizeof(int) + Example<char>::value;


                                and the value in Example<char> is



                                value = sizeof(char) + Example<>::value;


                                Now, for Example<>::value, the zero-parameters specialization is selected and Example<>::value is zero.



                                Concluding, we have that value in Example<long, int, char> is initialized with



                                 value = sizeof(long) + sizeof(int) + sizeof(char) + 0;


                                You tagged C++11, so it's a pity you can't use C++17 (template folding) where you can avoid recursion at all and define Example as a using



                                template <typename ... Ts>
                                using Example = std::integral_constant<std::size_t, (... + sizeof(Ts))>;





                                share|improve this answer






























                                  1















                                  Also why does the first template+class declaration is lacking "< S...>" right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?




                                  It seems to me that is better to start from this point.



                                  First of all, the following (removed the <S...> commented) is a declaration (attention: declaration only, not definition) of a template struct Example that receive a variadic list of type template parameters



                                  template<typename... S>
                                  struct Example;


                                  You can also avoid to use the S and write simply



                                  template <typename...>
                                  struct Example;


                                  because the name of the variadic list isn't used in this context.



                                  At this point the compiler know that there is a variadic template struct Example but doesn't know how is made.



                                  Next we add the definition of a specialization of Example that receive one or more template parameter (observe that Example is defined to receive zero or more parameter, so a specialization that receive one or more parameter is special case of Example)



                                  //....... one --> V          VVVVV <- or more template parameter
                                  template<typename H, typename... T>
                                  struct Example<H, T...>
                                  { // .........^^^^^^^^^ <- this is a specialization
                                  static const size_t value = sizeof(H) + Example<T...>::value;
                                  };


                                  The <H, T...> part after Example identifies a specialization (as said).



                                  This specialization define a static const size_t variable initialized with the sum of the sizeof(H) (the sizeof() of the first type template parameter) with the value defined in another Example class: Example<T...>.



                                  So you're observing a recursive definition: value is the sum of the sizeof() of the first parameter (a type) with the sum of the sizeof() of the following types.



                                  Suggestion: if you use variadic templates, you can use also constexpr, so better define value as constexpr



                                   static constexpr std::size_t value = sizeof(H) + Example<T...>::value;


                                  Or better, you can inherit from std::integral_constant



                                  template <typename H, typename... T>
                                  struct Example <H, T...>
                                  : public std::integral_constant<std::size_t, sizeof(H) + Example<T...>{}>
                                  { };


                                  so you inherit value from std::integral_constant with additional useful facilities (by example: automatic conversion to std::size_t in a context where a std::size_t is required)



                                  Every recursion needs a ground case, so you have



                                  template<>
                                  struct Example<>
                                  {
                                  static const size_t value = 0;
                                  };


                                  the declaration of another specialization of Example; this time the case with exactly zero template parameter (Example<>). In this case you have the definition of a value that is zero to terminate the recursion.



                                  As before, you can define value as constexpr or, better IMHO, using again std::integral_constant



                                  template <>
                                  struct Example<> : public std::integral_constant<std::size_t, 0u>
                                  { };


                                  Now you have defined two specializations for Example: one for the one-or-more parameters cases, one for the zero-parameters case. So you have covered all cases for Example that is declared receiving zero-or-more parameters; there is no needs to declare the generic (not specialized version) of Example.



                                  As observed by Deduplicator, you can define the generic case and only one specialization: if you write



                                  template <typename...>
                                  struct Example : public std::integral_constant<std::size_t, 0u>
                                  { };

                                  template <typename T, typename ... Ts>
                                  struct Example<T, Ts...>
                                  : public std::integral_constant<std::size_t, sizeof(T)+Example<Ts...>{}>
                                  { };


                                  you first declare Example receiving zero-or-more parameters and define the generic case with a value zero (the ground case), next you define a one-or-more specialization.



                                  Considering that the compiler select the more specialized version (when more version matches), the compiler select the specialization when there is one-or-more parameters (bot versions match but the specialization is more specialized) and the generic version when there are zero parameters (because the specialization doesn't matches).



                                  This way is a little more synthetic but can be less clear.




                                  Could you please describe what will happen for the below call? which of the templates will be used and when?




                                  Now should be simple to understand.



                                  When you write



                                  Example<long, int, char>::value


                                  you ask for the value of Example<long, int, char>.



                                  Three parameters, so the one-or-more specialization is selected, that is



                                  value = sizeof(long) + Example<int, char>::value;


                                  for the same reason, the value in Example<int, char> is



                                  value = sizeof(int) + Example<char>::value;


                                  and the value in Example<char> is



                                  value = sizeof(char) + Example<>::value;


                                  Now, for Example<>::value, the zero-parameters specialization is selected and Example<>::value is zero.



                                  Concluding, we have that value in Example<long, int, char> is initialized with



                                   value = sizeof(long) + sizeof(int) + sizeof(char) + 0;


                                  You tagged C++11, so it's a pity you can't use C++17 (template folding) where you can avoid recursion at all and define Example as a using



                                  template <typename ... Ts>
                                  using Example = std::integral_constant<std::size_t, (... + sizeof(Ts))>;





                                  share|improve this answer




























                                    1












                                    1








                                    1








                                    Also why does the first template+class declaration is lacking "< S...>" right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?




                                    It seems to me that is better to start from this point.



                                    First of all, the following (removed the <S...> commented) is a declaration (attention: declaration only, not definition) of a template struct Example that receive a variadic list of type template parameters



                                    template<typename... S>
                                    struct Example;


                                    You can also avoid to use the S and write simply



                                    template <typename...>
                                    struct Example;


                                    because the name of the variadic list isn't used in this context.



                                    At this point the compiler know that there is a variadic template struct Example but doesn't know how is made.



                                    Next we add the definition of a specialization of Example that receive one or more template parameter (observe that Example is defined to receive zero or more parameter, so a specialization that receive one or more parameter is special case of Example)



                                    //....... one --> V          VVVVV <- or more template parameter
                                    template<typename H, typename... T>
                                    struct Example<H, T...>
                                    { // .........^^^^^^^^^ <- this is a specialization
                                    static const size_t value = sizeof(H) + Example<T...>::value;
                                    };


                                    The <H, T...> part after Example identifies a specialization (as said).



                                    This specialization define a static const size_t variable initialized with the sum of the sizeof(H) (the sizeof() of the first type template parameter) with the value defined in another Example class: Example<T...>.



                                    So you're observing a recursive definition: value is the sum of the sizeof() of the first parameter (a type) with the sum of the sizeof() of the following types.



                                    Suggestion: if you use variadic templates, you can use also constexpr, so better define value as constexpr



                                     static constexpr std::size_t value = sizeof(H) + Example<T...>::value;


                                    Or better, you can inherit from std::integral_constant



                                    template <typename H, typename... T>
                                    struct Example <H, T...>
                                    : public std::integral_constant<std::size_t, sizeof(H) + Example<T...>{}>
                                    { };


                                    so you inherit value from std::integral_constant with additional useful facilities (by example: automatic conversion to std::size_t in a context where a std::size_t is required)



                                    Every recursion needs a ground case, so you have



                                    template<>
                                    struct Example<>
                                    {
                                    static const size_t value = 0;
                                    };


                                    the declaration of another specialization of Example; this time the case with exactly zero template parameter (Example<>). In this case you have the definition of a value that is zero to terminate the recursion.



                                    As before, you can define value as constexpr or, better IMHO, using again std::integral_constant



                                    template <>
                                    struct Example<> : public std::integral_constant<std::size_t, 0u>
                                    { };


                                    Now you have defined two specializations for Example: one for the one-or-more parameters cases, one for the zero-parameters case. So you have covered all cases for Example that is declared receiving zero-or-more parameters; there is no needs to declare the generic (not specialized version) of Example.



                                    As observed by Deduplicator, you can define the generic case and only one specialization: if you write



                                    template <typename...>
                                    struct Example : public std::integral_constant<std::size_t, 0u>
                                    { };

                                    template <typename T, typename ... Ts>
                                    struct Example<T, Ts...>
                                    : public std::integral_constant<std::size_t, sizeof(T)+Example<Ts...>{}>
                                    { };


                                    you first declare Example receiving zero-or-more parameters and define the generic case with a value zero (the ground case), next you define a one-or-more specialization.



                                    Considering that the compiler select the more specialized version (when more version matches), the compiler select the specialization when there is one-or-more parameters (bot versions match but the specialization is more specialized) and the generic version when there are zero parameters (because the specialization doesn't matches).



                                    This way is a little more synthetic but can be less clear.




                                    Could you please describe what will happen for the below call? which of the templates will be used and when?




                                    Now should be simple to understand.



                                    When you write



                                    Example<long, int, char>::value


                                    you ask for the value of Example<long, int, char>.



                                    Three parameters, so the one-or-more specialization is selected, that is



                                    value = sizeof(long) + Example<int, char>::value;


                                    for the same reason, the value in Example<int, char> is



                                    value = sizeof(int) + Example<char>::value;


                                    and the value in Example<char> is



                                    value = sizeof(char) + Example<>::value;


                                    Now, for Example<>::value, the zero-parameters specialization is selected and Example<>::value is zero.



                                    Concluding, we have that value in Example<long, int, char> is initialized with



                                     value = sizeof(long) + sizeof(int) + sizeof(char) + 0;


                                    You tagged C++11, so it's a pity you can't use C++17 (template folding) where you can avoid recursion at all and define Example as a using



                                    template <typename ... Ts>
                                    using Example = std::integral_constant<std::size_t, (... + sizeof(Ts))>;





                                    share|improve this answer
















                                    Also why does the first template+class declaration is lacking "< S...>" right after the struct declaration?(see what's commented out)? when it's right to add it and when it's not?




                                    It seems to me that is better to start from this point.



                                    First of all, the following (removed the <S...> commented) is a declaration (attention: declaration only, not definition) of a template struct Example that receive a variadic list of type template parameters



                                    template<typename... S>
                                    struct Example;


                                    You can also avoid to use the S and write simply



                                    template <typename...>
                                    struct Example;


                                    because the name of the variadic list isn't used in this context.



                                    At this point the compiler know that there is a variadic template struct Example but doesn't know how is made.



                                    Next we add the definition of a specialization of Example that receive one or more template parameter (observe that Example is defined to receive zero or more parameter, so a specialization that receive one or more parameter is special case of Example)



                                    //....... one --> V          VVVVV <- or more template parameter
                                    template<typename H, typename... T>
                                    struct Example<H, T...>
                                    { // .........^^^^^^^^^ <- this is a specialization
                                    static const size_t value = sizeof(H) + Example<T...>::value;
                                    };


                                    The <H, T...> part after Example identifies a specialization (as said).



                                    This specialization define a static const size_t variable initialized with the sum of the sizeof(H) (the sizeof() of the first type template parameter) with the value defined in another Example class: Example<T...>.



                                    So you're observing a recursive definition: value is the sum of the sizeof() of the first parameter (a type) with the sum of the sizeof() of the following types.



                                    Suggestion: if you use variadic templates, you can use also constexpr, so better define value as constexpr



                                     static constexpr std::size_t value = sizeof(H) + Example<T...>::value;


                                    Or better, you can inherit from std::integral_constant



                                    template <typename H, typename... T>
                                    struct Example <H, T...>
                                    : public std::integral_constant<std::size_t, sizeof(H) + Example<T...>{}>
                                    { };


                                    so you inherit value from std::integral_constant with additional useful facilities (by example: automatic conversion to std::size_t in a context where a std::size_t is required)



                                    Every recursion needs a ground case, so you have



                                    template<>
                                    struct Example<>
                                    {
                                    static const size_t value = 0;
                                    };


                                    the declaration of another specialization of Example; this time the case with exactly zero template parameter (Example<>). In this case you have the definition of a value that is zero to terminate the recursion.



                                    As before, you can define value as constexpr or, better IMHO, using again std::integral_constant



                                    template <>
                                    struct Example<> : public std::integral_constant<std::size_t, 0u>
                                    { };


                                    Now you have defined two specializations for Example: one for the one-or-more parameters cases, one for the zero-parameters case. So you have covered all cases for Example that is declared receiving zero-or-more parameters; there is no needs to declare the generic (not specialized version) of Example.



                                    As observed by Deduplicator, you can define the generic case and only one specialization: if you write



                                    template <typename...>
                                    struct Example : public std::integral_constant<std::size_t, 0u>
                                    { };

                                    template <typename T, typename ... Ts>
                                    struct Example<T, Ts...>
                                    : public std::integral_constant<std::size_t, sizeof(T)+Example<Ts...>{}>
                                    { };


                                    you first declare Example receiving zero-or-more parameters and define the generic case with a value zero (the ground case), next you define a one-or-more specialization.



                                    Considering that the compiler select the more specialized version (when more version matches), the compiler select the specialization when there is one-or-more parameters (bot versions match but the specialization is more specialized) and the generic version when there are zero parameters (because the specialization doesn't matches).



                                    This way is a little more synthetic but can be less clear.




                                    Could you please describe what will happen for the below call? which of the templates will be used and when?




                                    Now should be simple to understand.



                                    When you write



                                    Example<long, int, char>::value


                                    you ask for the value of Example<long, int, char>.



                                    Three parameters, so the one-or-more specialization is selected, that is



                                    value = sizeof(long) + Example<int, char>::value;


                                    for the same reason, the value in Example<int, char> is



                                    value = sizeof(int) + Example<char>::value;


                                    and the value in Example<char> is



                                    value = sizeof(char) + Example<>::value;


                                    Now, for Example<>::value, the zero-parameters specialization is selected and Example<>::value is zero.



                                    Concluding, we have that value in Example<long, int, char> is initialized with



                                     value = sizeof(long) + sizeof(int) + sizeof(char) + 0;


                                    You tagged C++11, so it's a pity you can't use C++17 (template folding) where you can avoid recursion at all and define Example as a using



                                    template <typename ... Ts>
                                    using Example = std::integral_constant<std::size_t, (... + sizeof(Ts))>;






                                    share|improve this answer














                                    share|improve this answer



                                    share|improve this answer








                                    edited 48 mins ago

























                                    answered 1 hour ago









                                    max66max66

                                    37.7k74370




                                    37.7k74370






















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










                                        draft saved

                                        draft discarded


















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













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












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
















                                        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%2f55109599%2fdeclaring-and-defining-template-and-specialising-them%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

                                        What are all the squawk codes?

                                        What are differences between VBoxVGA, VMSVGA and VBoxSVGA in VirtualBox?

                                        Hudsonelva