Why does accumulate in C++ have two templates defined

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











up vote
6
down vote

favorite
1












Why does accumulate in C++ have two templates defined when the job can be done with just one template (the one with the binaryOperation and default value to sum)?
I am referring to the accumulate declaration from http://www.cplusplus.com/reference/numeric/accumulate/










share|improve this question









New contributor




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



















  • What should be the default value to sum in your opinion?
    – Yksisarvinen
    2 hours ago










  • @Yksisarvinen: std::plus?
    – Vittorio Romeo
    2 hours ago







  • 2




    en.cppreference.com/w/cpp/algorithm/accumulate "The first version uses operator+ to sum up the elements, the second version uses the given binary function op"
    – hellow
    2 hours ago










  • As it is already said in one of the answers, it is a matter of taste. You have an article about it here fluentcpp.com/2018/08/07/…
    – PeMaCN
    2 hours ago















up vote
6
down vote

favorite
1












Why does accumulate in C++ have two templates defined when the job can be done with just one template (the one with the binaryOperation and default value to sum)?
I am referring to the accumulate declaration from http://www.cplusplus.com/reference/numeric/accumulate/










share|improve this question









New contributor




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



















  • What should be the default value to sum in your opinion?
    – Yksisarvinen
    2 hours ago










  • @Yksisarvinen: std::plus?
    – Vittorio Romeo
    2 hours ago







  • 2




    en.cppreference.com/w/cpp/algorithm/accumulate "The first version uses operator+ to sum up the elements, the second version uses the given binary function op"
    – hellow
    2 hours ago










  • As it is already said in one of the answers, it is a matter of taste. You have an article about it here fluentcpp.com/2018/08/07/…
    – PeMaCN
    2 hours ago













up vote
6
down vote

favorite
1









up vote
6
down vote

favorite
1






1





Why does accumulate in C++ have two templates defined when the job can be done with just one template (the one with the binaryOperation and default value to sum)?
I am referring to the accumulate declaration from http://www.cplusplus.com/reference/numeric/accumulate/










share|improve this question









New contributor




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











Why does accumulate in C++ have two templates defined when the job can be done with just one template (the one with the binaryOperation and default value to sum)?
I am referring to the accumulate declaration from http://www.cplusplus.com/reference/numeric/accumulate/







c++






share|improve this question









New contributor




NIKESH SINGH 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




NIKESH SINGH 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 2 hours ago









dandan78

9,56295068




9,56295068






New contributor




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









asked 3 hours ago









NIKESH SINGH

371




371




New contributor




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





New contributor





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






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











  • What should be the default value to sum in your opinion?
    – Yksisarvinen
    2 hours ago










  • @Yksisarvinen: std::plus?
    – Vittorio Romeo
    2 hours ago







  • 2




    en.cppreference.com/w/cpp/algorithm/accumulate "The first version uses operator+ to sum up the elements, the second version uses the given binary function op"
    – hellow
    2 hours ago










  • As it is already said in one of the answers, it is a matter of taste. You have an article about it here fluentcpp.com/2018/08/07/…
    – PeMaCN
    2 hours ago

















  • What should be the default value to sum in your opinion?
    – Yksisarvinen
    2 hours ago










  • @Yksisarvinen: std::plus?
    – Vittorio Romeo
    2 hours ago







  • 2




    en.cppreference.com/w/cpp/algorithm/accumulate "The first version uses operator+ to sum up the elements, the second version uses the given binary function op"
    – hellow
    2 hours ago










  • As it is already said in one of the answers, it is a matter of taste. You have an article about it here fluentcpp.com/2018/08/07/…
    – PeMaCN
    2 hours ago
















What should be the default value to sum in your opinion?
– Yksisarvinen
2 hours ago




What should be the default value to sum in your opinion?
– Yksisarvinen
2 hours ago












@Yksisarvinen: std::plus?
– Vittorio Romeo
2 hours ago





@Yksisarvinen: std::plus?
– Vittorio Romeo
2 hours ago





2




2




en.cppreference.com/w/cpp/algorithm/accumulate "The first version uses operator+ to sum up the elements, the second version uses the given binary function op"
– hellow
2 hours ago




en.cppreference.com/w/cpp/algorithm/accumulate "The first version uses operator+ to sum up the elements, the second version uses the given binary function op"
– hellow
2 hours ago












As it is already said in one of the answers, it is a matter of taste. You have an article about it here fluentcpp.com/2018/08/07/…
– PeMaCN
2 hours ago





As it is already said in one of the answers, it is a matter of taste. You have an article about it here fluentcpp.com/2018/08/07/…
– PeMaCN
2 hours ago













4 Answers
4






active

oldest

votes

















up vote
7
down vote













Because that's how the standard has been specified.



It is often a matter of taste whether to use an overload or a default argument. In this case, overload was chosen (by committee, by Alexander Stepanov, or by whoever happened to be responsible for the choice).



Default values are more limited than overloads. For example, you can have a function pointer T (*)(InputIterator, InputIterator, T) pointing to the first overload, which would not be possible if there was only one function (template) with 4 arguments. This flexibility can be used as an argument for using overloads rather than default arguments when possible.






share|improve this answer


















  • 2




    This. And I'm not sure all the machinery was there to make only one overload in 98. In C++14 it's easy though.
    – StoryTeller
    2 hours ago










  • @StoryTeller if you had a single declaration template <typename It, typename T, typename Op = plus<>> It accumulate(It, It, T, Op = ) don't you have issues with non-default-constructible operations? Or does the fact that it isn't using the default parameter make it OK?
    – Caleth
    2 hours ago











  • @Caleth A default function argument that is not used is ignored entirely. So using that declaration, accumulate(c.begin(), c.end(), 0, (auto& x, auto& y) return x+y*y; ) would remain valid, even though a closure type cannot be default-initialized.
    – aschepler
    1 hour ago











  • @Caleth Well "ignored entirely" is a simplification. More exactly, every default argument must always have valid syntax, and for a non-template function, the semantics of a default argument and initializing the function parameter with that expression must be valid even if the argument is never used. But for a template function, each default argument is considered to be separately instantiated from the function declaration itself and any other default arguments, and only if that default argument is actually used.
    – aschepler
    1 hour ago


















up vote
4
down vote













It's true you would get mostly the same behavior from a single template like



template <class InputIt, class T, class BinaryOperation = std::plus<>>
accumulate(InputIt first, InputIt last, T init, BinaryOperation op = );


But note that in earlier versions of C++, this would be difficult or impossible:



  • Prior to C++11, a function template could not have default template arguments.

  • Prior to C++14, std::plus<> (which is the same as std::plus<void>) was not valid: the class template could only be instantiated with one specific argument type.

  • The accumulate template is even older than the first C++ Standard of 1998: it goes back to the SGI STL library. At that time, compiler support for templates was rather inconsistent, so it was advisable to keep templates as simple as possible.

So the original two declarations were kept. As noted in bobah's answer, combining them into one declaration could break existing code, since for example code might be using a function pointer to an instantiation of the three-argument version (and function pointers cannot represent a default function argument, whether the function is from a template or not).



Sometimes the Standard library will add additional overloads to an existing function, but usually only for a specific purpose that would improve the interface, and when possible without breaking old code. There hasn't been any such reason for std::accumulate.



(But note member functions in the standard library can change more often than non-member functions like std::accumulate. The Standard gives implementations permission to declare member functions with different overloads, default arguments, etc. than specified as long as the effects are as described. This means it's generally a bad idea to take pointers to member functions to standard library class members, or otherwise assume very specific declarations, in the first place.)






share|improve this answer





























    up vote
    0
    down vote













    The motivtion for the 2 functions is the same reason that we have both a copy and a transform function, to give the coder the flexability to apply a function on a per element basis. But perhaps some real world code would be helpful in understanding where this would be used. I've used both these snipits professionally in coding:



    The 1st instance of accumulate can be used to sum the elements of a range. For example, given const int input = 13, 42 I can do this to get the sum of all elements in input:



    accumulate(cbegin(input), cend(input), 0) /* Returns 55 */


    I personally most commonly use the 2nd instance to generate strings (because it's the closest thing c++ has to a join) but it can also be used when special preprocessing is needed before the element is added. For example:



    accumulate(next(cbegin(input)), cend(input), to_string(front(input)), (const auto& current_sum, const auto i) return current_sum + ", " + to_string(i); ) /* Returns "13, 42"s */



    It's worth noting P0616R0 when considering my use of the 2nd function. This proposal has been accepted into c++20 and will move rather than copy the first parameter to accumulate's functor, which, "Can lead to massive improvements (particularly, it
    means accumulating strings is linear rather than quadratic)."






    share|improve this answer





























      up vote
      -1
      down vote













      One guess is, it could be because for std::plus to be as fast as + for primitive types one needs a good quality optimizing compiler, correct compilation flags, and the templated code should not be too deep (compilers have inlining thresholds).






      share|improve this answer






















      • I downvoted because this doesn't answer OP (and it's just a guess). The more general overload could have its last parameter defaulted to something like std::plus. The caller side readability won't be affected.
        – Vittorio Romeo
        2 hours ago










      • It is not a guess. The "probably" was related to "the most typical usecase" only. And my subjective preference is to not type verbose signature when can be avoided, that's one of the reasons C++ is so great.
        – bobah
        2 hours ago











      • I fail to see your point. Are you claiming that it makes the Standard Library implementation code more readable? If so, I disagree as there now is code repetition.
        – Vittorio Romeo
        2 hours ago










      • accumulate(vals.begin(), vals.end(), 0.0) is less verbose and therefore more readable than accumulate(vals.begin(), vals.end(), 0.0, std::plus) nothing to do with the implementation. Not mentioning that the latter may have different performance profile if inlining of std::plus fails (or when -O0 is used).
        – bobah
        2 hours ago











      • The whole point of the OP's question is having std::plus (or some implementation-defined callable) as a default parameter to the more flexible overload. The caller syntax would not change.
        – Vittorio Romeo
        2 hours ago











      Your Answer





      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      convertImagesToLinks: true,
      noModals: false,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );






      NIKESH SINGH 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%2f52442628%2fwhy-does-accumulate-in-c-have-two-templates-defined%23new-answer', 'question_page');

      );

      Post as a guest






























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      7
      down vote













      Because that's how the standard has been specified.



      It is often a matter of taste whether to use an overload or a default argument. In this case, overload was chosen (by committee, by Alexander Stepanov, or by whoever happened to be responsible for the choice).



      Default values are more limited than overloads. For example, you can have a function pointer T (*)(InputIterator, InputIterator, T) pointing to the first overload, which would not be possible if there was only one function (template) with 4 arguments. This flexibility can be used as an argument for using overloads rather than default arguments when possible.






      share|improve this answer


















      • 2




        This. And I'm not sure all the machinery was there to make only one overload in 98. In C++14 it's easy though.
        – StoryTeller
        2 hours ago










      • @StoryTeller if you had a single declaration template <typename It, typename T, typename Op = plus<>> It accumulate(It, It, T, Op = ) don't you have issues with non-default-constructible operations? Or does the fact that it isn't using the default parameter make it OK?
        – Caleth
        2 hours ago











      • @Caleth A default function argument that is not used is ignored entirely. So using that declaration, accumulate(c.begin(), c.end(), 0, (auto& x, auto& y) return x+y*y; ) would remain valid, even though a closure type cannot be default-initialized.
        – aschepler
        1 hour ago











      • @Caleth Well "ignored entirely" is a simplification. More exactly, every default argument must always have valid syntax, and for a non-template function, the semantics of a default argument and initializing the function parameter with that expression must be valid even if the argument is never used. But for a template function, each default argument is considered to be separately instantiated from the function declaration itself and any other default arguments, and only if that default argument is actually used.
        – aschepler
        1 hour ago















      up vote
      7
      down vote













      Because that's how the standard has been specified.



      It is often a matter of taste whether to use an overload or a default argument. In this case, overload was chosen (by committee, by Alexander Stepanov, or by whoever happened to be responsible for the choice).



      Default values are more limited than overloads. For example, you can have a function pointer T (*)(InputIterator, InputIterator, T) pointing to the first overload, which would not be possible if there was only one function (template) with 4 arguments. This flexibility can be used as an argument for using overloads rather than default arguments when possible.






      share|improve this answer


















      • 2




        This. And I'm not sure all the machinery was there to make only one overload in 98. In C++14 it's easy though.
        – StoryTeller
        2 hours ago










      • @StoryTeller if you had a single declaration template <typename It, typename T, typename Op = plus<>> It accumulate(It, It, T, Op = ) don't you have issues with non-default-constructible operations? Or does the fact that it isn't using the default parameter make it OK?
        – Caleth
        2 hours ago











      • @Caleth A default function argument that is not used is ignored entirely. So using that declaration, accumulate(c.begin(), c.end(), 0, (auto& x, auto& y) return x+y*y; ) would remain valid, even though a closure type cannot be default-initialized.
        – aschepler
        1 hour ago











      • @Caleth Well "ignored entirely" is a simplification. More exactly, every default argument must always have valid syntax, and for a non-template function, the semantics of a default argument and initializing the function parameter with that expression must be valid even if the argument is never used. But for a template function, each default argument is considered to be separately instantiated from the function declaration itself and any other default arguments, and only if that default argument is actually used.
        – aschepler
        1 hour ago













      up vote
      7
      down vote










      up vote
      7
      down vote









      Because that's how the standard has been specified.



      It is often a matter of taste whether to use an overload or a default argument. In this case, overload was chosen (by committee, by Alexander Stepanov, or by whoever happened to be responsible for the choice).



      Default values are more limited than overloads. For example, you can have a function pointer T (*)(InputIterator, InputIterator, T) pointing to the first overload, which would not be possible if there was only one function (template) with 4 arguments. This flexibility can be used as an argument for using overloads rather than default arguments when possible.






      share|improve this answer














      Because that's how the standard has been specified.



      It is often a matter of taste whether to use an overload or a default argument. In this case, overload was chosen (by committee, by Alexander Stepanov, or by whoever happened to be responsible for the choice).



      Default values are more limited than overloads. For example, you can have a function pointer T (*)(InputIterator, InputIterator, T) pointing to the first overload, which would not be possible if there was only one function (template) with 4 arguments. This flexibility can be used as an argument for using overloads rather than default arguments when possible.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited 2 hours ago

























      answered 2 hours ago









      user2079303

      69.1k550109




      69.1k550109







      • 2




        This. And I'm not sure all the machinery was there to make only one overload in 98. In C++14 it's easy though.
        – StoryTeller
        2 hours ago










      • @StoryTeller if you had a single declaration template <typename It, typename T, typename Op = plus<>> It accumulate(It, It, T, Op = ) don't you have issues with non-default-constructible operations? Or does the fact that it isn't using the default parameter make it OK?
        – Caleth
        2 hours ago











      • @Caleth A default function argument that is not used is ignored entirely. So using that declaration, accumulate(c.begin(), c.end(), 0, (auto& x, auto& y) return x+y*y; ) would remain valid, even though a closure type cannot be default-initialized.
        – aschepler
        1 hour ago











      • @Caleth Well "ignored entirely" is a simplification. More exactly, every default argument must always have valid syntax, and for a non-template function, the semantics of a default argument and initializing the function parameter with that expression must be valid even if the argument is never used. But for a template function, each default argument is considered to be separately instantiated from the function declaration itself and any other default arguments, and only if that default argument is actually used.
        – aschepler
        1 hour ago













      • 2




        This. And I'm not sure all the machinery was there to make only one overload in 98. In C++14 it's easy though.
        – StoryTeller
        2 hours ago










      • @StoryTeller if you had a single declaration template <typename It, typename T, typename Op = plus<>> It accumulate(It, It, T, Op = ) don't you have issues with non-default-constructible operations? Or does the fact that it isn't using the default parameter make it OK?
        – Caleth
        2 hours ago











      • @Caleth A default function argument that is not used is ignored entirely. So using that declaration, accumulate(c.begin(), c.end(), 0, (auto& x, auto& y) return x+y*y; ) would remain valid, even though a closure type cannot be default-initialized.
        – aschepler
        1 hour ago











      • @Caleth Well "ignored entirely" is a simplification. More exactly, every default argument must always have valid syntax, and for a non-template function, the semantics of a default argument and initializing the function parameter with that expression must be valid even if the argument is never used. But for a template function, each default argument is considered to be separately instantiated from the function declaration itself and any other default arguments, and only if that default argument is actually used.
        – aschepler
        1 hour ago








      2




      2




      This. And I'm not sure all the machinery was there to make only one overload in 98. In C++14 it's easy though.
      – StoryTeller
      2 hours ago




      This. And I'm not sure all the machinery was there to make only one overload in 98. In C++14 it's easy though.
      – StoryTeller
      2 hours ago












      @StoryTeller if you had a single declaration template <typename It, typename T, typename Op = plus<>> It accumulate(It, It, T, Op = ) don't you have issues with non-default-constructible operations? Or does the fact that it isn't using the default parameter make it OK?
      – Caleth
      2 hours ago





      @StoryTeller if you had a single declaration template <typename It, typename T, typename Op = plus<>> It accumulate(It, It, T, Op = ) don't you have issues with non-default-constructible operations? Or does the fact that it isn't using the default parameter make it OK?
      – Caleth
      2 hours ago













      @Caleth A default function argument that is not used is ignored entirely. So using that declaration, accumulate(c.begin(), c.end(), 0, (auto& x, auto& y) return x+y*y; ) would remain valid, even though a closure type cannot be default-initialized.
      – aschepler
      1 hour ago





      @Caleth A default function argument that is not used is ignored entirely. So using that declaration, accumulate(c.begin(), c.end(), 0, (auto& x, auto& y) return x+y*y; ) would remain valid, even though a closure type cannot be default-initialized.
      – aschepler
      1 hour ago













      @Caleth Well "ignored entirely" is a simplification. More exactly, every default argument must always have valid syntax, and for a non-template function, the semantics of a default argument and initializing the function parameter with that expression must be valid even if the argument is never used. But for a template function, each default argument is considered to be separately instantiated from the function declaration itself and any other default arguments, and only if that default argument is actually used.
      – aschepler
      1 hour ago





      @Caleth Well "ignored entirely" is a simplification. More exactly, every default argument must always have valid syntax, and for a non-template function, the semantics of a default argument and initializing the function parameter with that expression must be valid even if the argument is never used. But for a template function, each default argument is considered to be separately instantiated from the function declaration itself and any other default arguments, and only if that default argument is actually used.
      – aschepler
      1 hour ago













      up vote
      4
      down vote













      It's true you would get mostly the same behavior from a single template like



      template <class InputIt, class T, class BinaryOperation = std::plus<>>
      accumulate(InputIt first, InputIt last, T init, BinaryOperation op = );


      But note that in earlier versions of C++, this would be difficult or impossible:



      • Prior to C++11, a function template could not have default template arguments.

      • Prior to C++14, std::plus<> (which is the same as std::plus<void>) was not valid: the class template could only be instantiated with one specific argument type.

      • The accumulate template is even older than the first C++ Standard of 1998: it goes back to the SGI STL library. At that time, compiler support for templates was rather inconsistent, so it was advisable to keep templates as simple as possible.

      So the original two declarations were kept. As noted in bobah's answer, combining them into one declaration could break existing code, since for example code might be using a function pointer to an instantiation of the three-argument version (and function pointers cannot represent a default function argument, whether the function is from a template or not).



      Sometimes the Standard library will add additional overloads to an existing function, but usually only for a specific purpose that would improve the interface, and when possible without breaking old code. There hasn't been any such reason for std::accumulate.



      (But note member functions in the standard library can change more often than non-member functions like std::accumulate. The Standard gives implementations permission to declare member functions with different overloads, default arguments, etc. than specified as long as the effects are as described. This means it's generally a bad idea to take pointers to member functions to standard library class members, or otherwise assume very specific declarations, in the first place.)






      share|improve this answer


























        up vote
        4
        down vote













        It's true you would get mostly the same behavior from a single template like



        template <class InputIt, class T, class BinaryOperation = std::plus<>>
        accumulate(InputIt first, InputIt last, T init, BinaryOperation op = );


        But note that in earlier versions of C++, this would be difficult or impossible:



        • Prior to C++11, a function template could not have default template arguments.

        • Prior to C++14, std::plus<> (which is the same as std::plus<void>) was not valid: the class template could only be instantiated with one specific argument type.

        • The accumulate template is even older than the first C++ Standard of 1998: it goes back to the SGI STL library. At that time, compiler support for templates was rather inconsistent, so it was advisable to keep templates as simple as possible.

        So the original two declarations were kept. As noted in bobah's answer, combining them into one declaration could break existing code, since for example code might be using a function pointer to an instantiation of the three-argument version (and function pointers cannot represent a default function argument, whether the function is from a template or not).



        Sometimes the Standard library will add additional overloads to an existing function, but usually only for a specific purpose that would improve the interface, and when possible without breaking old code. There hasn't been any such reason for std::accumulate.



        (But note member functions in the standard library can change more often than non-member functions like std::accumulate. The Standard gives implementations permission to declare member functions with different overloads, default arguments, etc. than specified as long as the effects are as described. This means it's generally a bad idea to take pointers to member functions to standard library class members, or otherwise assume very specific declarations, in the first place.)






        share|improve this answer
























          up vote
          4
          down vote










          up vote
          4
          down vote









          It's true you would get mostly the same behavior from a single template like



          template <class InputIt, class T, class BinaryOperation = std::plus<>>
          accumulate(InputIt first, InputIt last, T init, BinaryOperation op = );


          But note that in earlier versions of C++, this would be difficult or impossible:



          • Prior to C++11, a function template could not have default template arguments.

          • Prior to C++14, std::plus<> (which is the same as std::plus<void>) was not valid: the class template could only be instantiated with one specific argument type.

          • The accumulate template is even older than the first C++ Standard of 1998: it goes back to the SGI STL library. At that time, compiler support for templates was rather inconsistent, so it was advisable to keep templates as simple as possible.

          So the original two declarations were kept. As noted in bobah's answer, combining them into one declaration could break existing code, since for example code might be using a function pointer to an instantiation of the three-argument version (and function pointers cannot represent a default function argument, whether the function is from a template or not).



          Sometimes the Standard library will add additional overloads to an existing function, but usually only for a specific purpose that would improve the interface, and when possible without breaking old code. There hasn't been any such reason for std::accumulate.



          (But note member functions in the standard library can change more often than non-member functions like std::accumulate. The Standard gives implementations permission to declare member functions with different overloads, default arguments, etc. than specified as long as the effects are as described. This means it's generally a bad idea to take pointers to member functions to standard library class members, or otherwise assume very specific declarations, in the first place.)






          share|improve this answer














          It's true you would get mostly the same behavior from a single template like



          template <class InputIt, class T, class BinaryOperation = std::plus<>>
          accumulate(InputIt first, InputIt last, T init, BinaryOperation op = );


          But note that in earlier versions of C++, this would be difficult or impossible:



          • Prior to C++11, a function template could not have default template arguments.

          • Prior to C++14, std::plus<> (which is the same as std::plus<void>) was not valid: the class template could only be instantiated with one specific argument type.

          • The accumulate template is even older than the first C++ Standard of 1998: it goes back to the SGI STL library. At that time, compiler support for templates was rather inconsistent, so it was advisable to keep templates as simple as possible.

          So the original two declarations were kept. As noted in bobah's answer, combining them into one declaration could break existing code, since for example code might be using a function pointer to an instantiation of the three-argument version (and function pointers cannot represent a default function argument, whether the function is from a template or not).



          Sometimes the Standard library will add additional overloads to an existing function, but usually only for a specific purpose that would improve the interface, and when possible without breaking old code. There hasn't been any such reason for std::accumulate.



          (But note member functions in the standard library can change more often than non-member functions like std::accumulate. The Standard gives implementations permission to declare member functions with different overloads, default arguments, etc. than specified as long as the effects are as described. This means it's generally a bad idea to take pointers to member functions to standard library class members, or otherwise assume very specific declarations, in the first place.)







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 1 hour ago

























          answered 1 hour ago









          aschepler

          50k569124




          50k569124




















              up vote
              0
              down vote













              The motivtion for the 2 functions is the same reason that we have both a copy and a transform function, to give the coder the flexability to apply a function on a per element basis. But perhaps some real world code would be helpful in understanding where this would be used. I've used both these snipits professionally in coding:



              The 1st instance of accumulate can be used to sum the elements of a range. For example, given const int input = 13, 42 I can do this to get the sum of all elements in input:



              accumulate(cbegin(input), cend(input), 0) /* Returns 55 */


              I personally most commonly use the 2nd instance to generate strings (because it's the closest thing c++ has to a join) but it can also be used when special preprocessing is needed before the element is added. For example:



              accumulate(next(cbegin(input)), cend(input), to_string(front(input)), (const auto& current_sum, const auto i) return current_sum + ", " + to_string(i); ) /* Returns "13, 42"s */



              It's worth noting P0616R0 when considering my use of the 2nd function. This proposal has been accepted into c++20 and will move rather than copy the first parameter to accumulate's functor, which, "Can lead to massive improvements (particularly, it
              means accumulating strings is linear rather than quadratic)."






              share|improve this answer


























                up vote
                0
                down vote













                The motivtion for the 2 functions is the same reason that we have both a copy and a transform function, to give the coder the flexability to apply a function on a per element basis. But perhaps some real world code would be helpful in understanding where this would be used. I've used both these snipits professionally in coding:



                The 1st instance of accumulate can be used to sum the elements of a range. For example, given const int input = 13, 42 I can do this to get the sum of all elements in input:



                accumulate(cbegin(input), cend(input), 0) /* Returns 55 */


                I personally most commonly use the 2nd instance to generate strings (because it's the closest thing c++ has to a join) but it can also be used when special preprocessing is needed before the element is added. For example:



                accumulate(next(cbegin(input)), cend(input), to_string(front(input)), (const auto& current_sum, const auto i) return current_sum + ", " + to_string(i); ) /* Returns "13, 42"s */



                It's worth noting P0616R0 when considering my use of the 2nd function. This proposal has been accepted into c++20 and will move rather than copy the first parameter to accumulate's functor, which, "Can lead to massive improvements (particularly, it
                means accumulating strings is linear rather than quadratic)."






                share|improve this answer
























                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  The motivtion for the 2 functions is the same reason that we have both a copy and a transform function, to give the coder the flexability to apply a function on a per element basis. But perhaps some real world code would be helpful in understanding where this would be used. I've used both these snipits professionally in coding:



                  The 1st instance of accumulate can be used to sum the elements of a range. For example, given const int input = 13, 42 I can do this to get the sum of all elements in input:



                  accumulate(cbegin(input), cend(input), 0) /* Returns 55 */


                  I personally most commonly use the 2nd instance to generate strings (because it's the closest thing c++ has to a join) but it can also be used when special preprocessing is needed before the element is added. For example:



                  accumulate(next(cbegin(input)), cend(input), to_string(front(input)), (const auto& current_sum, const auto i) return current_sum + ", " + to_string(i); ) /* Returns "13, 42"s */



                  It's worth noting P0616R0 when considering my use of the 2nd function. This proposal has been accepted into c++20 and will move rather than copy the first parameter to accumulate's functor, which, "Can lead to massive improvements (particularly, it
                  means accumulating strings is linear rather than quadratic)."






                  share|improve this answer














                  The motivtion for the 2 functions is the same reason that we have both a copy and a transform function, to give the coder the flexability to apply a function on a per element basis. But perhaps some real world code would be helpful in understanding where this would be used. I've used both these snipits professionally in coding:



                  The 1st instance of accumulate can be used to sum the elements of a range. For example, given const int input = 13, 42 I can do this to get the sum of all elements in input:



                  accumulate(cbegin(input), cend(input), 0) /* Returns 55 */


                  I personally most commonly use the 2nd instance to generate strings (because it's the closest thing c++ has to a join) but it can also be used when special preprocessing is needed before the element is added. For example:



                  accumulate(next(cbegin(input)), cend(input), to_string(front(input)), (const auto& current_sum, const auto i) return current_sum + ", " + to_string(i); ) /* Returns "13, 42"s */



                  It's worth noting P0616R0 when considering my use of the 2nd function. This proposal has been accepted into c++20 and will move rather than copy the first parameter to accumulate's functor, which, "Can lead to massive improvements (particularly, it
                  means accumulating strings is linear rather than quadratic)."







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited 1 hour ago

























                  answered 1 hour ago









                  Jonathan Mee

                  20.5k860153




                  20.5k860153




















                      up vote
                      -1
                      down vote













                      One guess is, it could be because for std::plus to be as fast as + for primitive types one needs a good quality optimizing compiler, correct compilation flags, and the templated code should not be too deep (compilers have inlining thresholds).






                      share|improve this answer






















                      • I downvoted because this doesn't answer OP (and it's just a guess). The more general overload could have its last parameter defaulted to something like std::plus. The caller side readability won't be affected.
                        – Vittorio Romeo
                        2 hours ago










                      • It is not a guess. The "probably" was related to "the most typical usecase" only. And my subjective preference is to not type verbose signature when can be avoided, that's one of the reasons C++ is so great.
                        – bobah
                        2 hours ago











                      • I fail to see your point. Are you claiming that it makes the Standard Library implementation code more readable? If so, I disagree as there now is code repetition.
                        – Vittorio Romeo
                        2 hours ago










                      • accumulate(vals.begin(), vals.end(), 0.0) is less verbose and therefore more readable than accumulate(vals.begin(), vals.end(), 0.0, std::plus) nothing to do with the implementation. Not mentioning that the latter may have different performance profile if inlining of std::plus fails (or when -O0 is used).
                        – bobah
                        2 hours ago











                      • The whole point of the OP's question is having std::plus (or some implementation-defined callable) as a default parameter to the more flexible overload. The caller syntax would not change.
                        – Vittorio Romeo
                        2 hours ago















                      up vote
                      -1
                      down vote













                      One guess is, it could be because for std::plus to be as fast as + for primitive types one needs a good quality optimizing compiler, correct compilation flags, and the templated code should not be too deep (compilers have inlining thresholds).






                      share|improve this answer






















                      • I downvoted because this doesn't answer OP (and it's just a guess). The more general overload could have its last parameter defaulted to something like std::plus. The caller side readability won't be affected.
                        – Vittorio Romeo
                        2 hours ago










                      • It is not a guess. The "probably" was related to "the most typical usecase" only. And my subjective preference is to not type verbose signature when can be avoided, that's one of the reasons C++ is so great.
                        – bobah
                        2 hours ago











                      • I fail to see your point. Are you claiming that it makes the Standard Library implementation code more readable? If so, I disagree as there now is code repetition.
                        – Vittorio Romeo
                        2 hours ago










                      • accumulate(vals.begin(), vals.end(), 0.0) is less verbose and therefore more readable than accumulate(vals.begin(), vals.end(), 0.0, std::plus) nothing to do with the implementation. Not mentioning that the latter may have different performance profile if inlining of std::plus fails (or when -O0 is used).
                        – bobah
                        2 hours ago











                      • The whole point of the OP's question is having std::plus (or some implementation-defined callable) as a default parameter to the more flexible overload. The caller syntax would not change.
                        – Vittorio Romeo
                        2 hours ago













                      up vote
                      -1
                      down vote










                      up vote
                      -1
                      down vote









                      One guess is, it could be because for std::plus to be as fast as + for primitive types one needs a good quality optimizing compiler, correct compilation flags, and the templated code should not be too deep (compilers have inlining thresholds).






                      share|improve this answer














                      One guess is, it could be because for std::plus to be as fast as + for primitive types one needs a good quality optimizing compiler, correct compilation flags, and the templated code should not be too deep (compilers have inlining thresholds).







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited 2 hours ago

























                      answered 2 hours ago









                      bobah

                      12.9k12246




                      12.9k12246











                      • I downvoted because this doesn't answer OP (and it's just a guess). The more general overload could have its last parameter defaulted to something like std::plus. The caller side readability won't be affected.
                        – Vittorio Romeo
                        2 hours ago










                      • It is not a guess. The "probably" was related to "the most typical usecase" only. And my subjective preference is to not type verbose signature when can be avoided, that's one of the reasons C++ is so great.
                        – bobah
                        2 hours ago











                      • I fail to see your point. Are you claiming that it makes the Standard Library implementation code more readable? If so, I disagree as there now is code repetition.
                        – Vittorio Romeo
                        2 hours ago










                      • accumulate(vals.begin(), vals.end(), 0.0) is less verbose and therefore more readable than accumulate(vals.begin(), vals.end(), 0.0, std::plus) nothing to do with the implementation. Not mentioning that the latter may have different performance profile if inlining of std::plus fails (or when -O0 is used).
                        – bobah
                        2 hours ago











                      • The whole point of the OP's question is having std::plus (or some implementation-defined callable) as a default parameter to the more flexible overload. The caller syntax would not change.
                        – Vittorio Romeo
                        2 hours ago

















                      • I downvoted because this doesn't answer OP (and it's just a guess). The more general overload could have its last parameter defaulted to something like std::plus. The caller side readability won't be affected.
                        – Vittorio Romeo
                        2 hours ago










                      • It is not a guess. The "probably" was related to "the most typical usecase" only. And my subjective preference is to not type verbose signature when can be avoided, that's one of the reasons C++ is so great.
                        – bobah
                        2 hours ago











                      • I fail to see your point. Are you claiming that it makes the Standard Library implementation code more readable? If so, I disagree as there now is code repetition.
                        – Vittorio Romeo
                        2 hours ago










                      • accumulate(vals.begin(), vals.end(), 0.0) is less verbose and therefore more readable than accumulate(vals.begin(), vals.end(), 0.0, std::plus) nothing to do with the implementation. Not mentioning that the latter may have different performance profile if inlining of std::plus fails (or when -O0 is used).
                        – bobah
                        2 hours ago











                      • The whole point of the OP's question is having std::plus (or some implementation-defined callable) as a default parameter to the more flexible overload. The caller syntax would not change.
                        – Vittorio Romeo
                        2 hours ago
















                      I downvoted because this doesn't answer OP (and it's just a guess). The more general overload could have its last parameter defaulted to something like std::plus. The caller side readability won't be affected.
                      – Vittorio Romeo
                      2 hours ago




                      I downvoted because this doesn't answer OP (and it's just a guess). The more general overload could have its last parameter defaulted to something like std::plus. The caller side readability won't be affected.
                      – Vittorio Romeo
                      2 hours ago












                      It is not a guess. The "probably" was related to "the most typical usecase" only. And my subjective preference is to not type verbose signature when can be avoided, that's one of the reasons C++ is so great.
                      – bobah
                      2 hours ago





                      It is not a guess. The "probably" was related to "the most typical usecase" only. And my subjective preference is to not type verbose signature when can be avoided, that's one of the reasons C++ is so great.
                      – bobah
                      2 hours ago













                      I fail to see your point. Are you claiming that it makes the Standard Library implementation code more readable? If so, I disagree as there now is code repetition.
                      – Vittorio Romeo
                      2 hours ago




                      I fail to see your point. Are you claiming that it makes the Standard Library implementation code more readable? If so, I disagree as there now is code repetition.
                      – Vittorio Romeo
                      2 hours ago












                      accumulate(vals.begin(), vals.end(), 0.0) is less verbose and therefore more readable than accumulate(vals.begin(), vals.end(), 0.0, std::plus) nothing to do with the implementation. Not mentioning that the latter may have different performance profile if inlining of std::plus fails (or when -O0 is used).
                      – bobah
                      2 hours ago





                      accumulate(vals.begin(), vals.end(), 0.0) is less verbose and therefore more readable than accumulate(vals.begin(), vals.end(), 0.0, std::plus) nothing to do with the implementation. Not mentioning that the latter may have different performance profile if inlining of std::plus fails (or when -O0 is used).
                      – bobah
                      2 hours ago













                      The whole point of the OP's question is having std::plus (or some implementation-defined callable) as a default parameter to the more flexible overload. The caller syntax would not change.
                      – Vittorio Romeo
                      2 hours ago





                      The whole point of the OP's question is having std::plus (or some implementation-defined callable) as a default parameter to the more flexible overload. The caller syntax would not change.
                      – Vittorio Romeo
                      2 hours ago











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









                       

                      draft saved


                      draft discarded


















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












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











                      NIKESH SINGH 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%2f52442628%2fwhy-does-accumulate-in-c-have-two-templates-defined%23new-answer', 'question_page');

                      );

                      Post as a guest













































































                      Comments

                      Popular posts from this blog

                      Long meetings (6-7 hours a day): Being “babysat” by supervisor

                      Is the Concept of Multiple Fantasy Races Scientifically Flawed? [closed]

                      Confectionery