Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #88145 > unrolled thread

Sum an array in a lambda.

Started byJoseph Hesse <joeh@gmail.com>
First post2022-12-20 11:00 -0600
Last post2022-12-22 19:55 +0100
Articles 10 — 7 participants

Back to article view | Back to comp.lang.c++


Contents

  Sum an array in a lambda. Joseph Hesse <joeh@gmail.com> - 2022-12-20 11:00 -0600
    Re: Sum an array in a lambda. Öö Tiib <ootiib@hot.ee> - 2022-12-20 09:29 -0800
      Re: Sum an array in a lambda. Joseph Hesse <joeh@gmail.com> - 2022-12-21 10:56 -0600
        Re: Sum an array in a lambda. Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2022-12-21 10:32 -0800
          Re: Sum an array in a lambda. Joseph Hesse <joeh@gmail.com> - 2022-12-22 00:05 -0600
            Re: Sum an array in a lambda. Öö Tiib <ootiib@hot.ee> - 2022-12-22 00:00 -0800
              Re: Sum an array in a lambda. Ben Bacarisse <ben.usenet@bsb.me.uk> - 2022-12-22 12:42 +0000
    Re: Sum an array in a lambda. Paavo Helde <eesnimi@osa.pri.ee> - 2022-12-20 20:03 +0200
    Re: Sum an array in a lambda. Juha Nieminen <nospam@thanks.invalid> - 2022-12-21 06:35 +0000
    Re: Sum an array in a lambda. Bonita Montero <Bonita.Montero@gmail.com> - 2022-12-22 19:55 +0100

#88145 — Sum an array in a lambda.

FromJoseph Hesse <joeh@gmail.com>
Date2022-12-20 11:00 -0600
SubjectSum an array in a lambda.
Message-ID<mMCcnTVp9u2wdzz-nZ2dnZfqnPudnZ2d@giganews.com>
I want to sum an array of int's in a lambda function.

In the following code, function f1 does this with no problem.

In function f2, I am able to sum an int array using a range based
for loop.  That this works surprises me since the array name is not 
converted to a pointer and the for loop "looks around" to find the
size of int x[].

The commented out code in f2 was my attempt, as in f1, to
put the code to sum the array in a lambda.  It does not compile.

Is it possible to make this work?

Thank you,
Joe
=======================================================
#include <iostream>
#include <vector>
using namespace std;

void f1(){
   vector<int> v = {1, 2, 3, 4};

   auto fp = [] (vector<int> vi)
   {
     int sum = 0;
     for(const int &i : vi)
       sum += i;
     return sum;
   };

   cout << "sum = " << fp(v) << '\n';
}

void f2(){
   int x[4] = {1, 2, 3, 4};

   int sum = 0;
   for(const int &i : x)
       sum += i;
   cout << "sum = " << sum << '\n';

/*
   auto fp = [] (int x[])
   {
     int sum = 0;
     for(const int &i : x)
       sum += i;
     return sum;
   };

   cout << "sum = " << fp(x) << '\n';
*/
}

int main(){
   f1();
   f2();
   return 0;
}

[toc] | [next] | [standalone]


#88146

FromÖö Tiib <ootiib@hot.ee>
Date2022-12-20 09:29 -0800
Message-ID<99ab1824-5934-428c-a586-0ee640bd5684n@googlegroups.com>
In reply to#88145
On Tuesday, 20 December 2022 at 19:00:49 UTC+2, Joseph Hesse wrote:
> I want to sum an array of int's in a lambda function. 
> 
> In the following code, function f1 does this with no problem. 
> 
> In function f2, I am able to sum an int array using a range based 
> for loop. That this works surprises me since the array name is not 
> converted to a pointer and the for loop "looks around" to find the 
> size of int x[]. 
> 
> The commented out code in f2 was my attempt, as in f1, to 
> put the code to sum the array in a lambda. It does not compile. 

The ...

auto fp = [] (int x[])

... is by language rules equivalent to ...

auto fp = [] (int *x)

... so array length information is lost and range 
based for has no idea what range you mean.

> 
> Is it possible to make this work? 

Sure, you should either use template ...

auto fp = []<size_t N>(int (&x)[N]) 

... or you should have fixed array reference ...

auto fp = [](int (&x)[4]) 

... then the range based for is happy with it.

 

[toc] | [prev] | [next] | [standalone]


#88198

FromJoseph Hesse <joeh@gmail.com>
Date2022-12-21 10:56 -0600
Message-ID<97GdnQ9Gd6Qhpz7-nZ2dnZfqnPudnZ2d@giganews.com>
In reply to#88146
On 12/20/22 11:29, Öö Tiib wrote:
> auto fp = [] (int x[])
> 
> ... is by language rules equivalent to ...
> 
> auto fp = [] (int *x)
> 
> ... so array length information is lost and range
> based for has no idea what range you mean.
> 
>>
> 
In the following program, the array definition and range based for loop 
are in the same scope so it appears that the range based for loop sees 
the size of the array.  The following program compiles with the gnu 
compiler and runs correctly.  I am surprised that it works.
=========================================
#include <iostream>
#include <vector>
using namespace std;
int main(){
   int x[4] = {1, 2, 3, 4};
   int sum = 0;
   for(const int &i : x)
       sum += i;
   cout << "sum = " << sum << '\n';
   return 0;
}

[toc] | [prev] | [next] | [standalone]


#88205

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2022-12-21 10:32 -0800
Message-ID<878rj0r4k4.fsf@nosuchdomain.example.com>
In reply to#88198
Joseph Hesse <joeh@gmail.com> writes:
> On 12/20/22 11:29, Öö Tiib wrote:
>> auto fp = [] (int x[])
>> ... is by language rules equivalent to ...
>> auto fp = [] (int *x)
>> ... so array length information is lost and range
>> based for has no idea what range you mean.
>> 
>>>
>> 
> In the following program, the array definition and range based for
> loop are in the same scope so it appears that the range based for loop
> sees the size of the array.  The following program compiles with the
> gnu compiler and runs correctly.  I am surprised that it works.
> =========================================
> #include <iostream>
> #include <vector>
> using namespace std;
> int main(){
>   int x[4] = {1, 2, 3, 4};
>   int sum = 0;
>   for(const int &i : x)
>       sum += i;
>   cout << "sum = " << sum << '\n';
>   return 0;
> }

Why are you surprised?

In `auto fp = [] (int x[])`, x is an array parameter, which is treated
as a pointer parameter.  That equivalence applies only to function
parameters.  In your example, you just have an array object.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for XCOM Labs
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#88212

FromJoseph Hesse <joeh@gmail.com>
Date2022-12-22 00:05 -0600
Message-ID<6LadnTLge6Mobj7-nZ2dnZfqnPSdnZ2d@giganews.com>
In reply to#88205
On 12/21/22 12:32, Keith Thompson wrote:
> Joseph Hesse <joeh@gmail.com> writes:
>> On 12/20/22 11:29, Öö Tiib wrote:
>>> auto fp = [] (int x[])
>>> ... is by language rules equivalent to ...
>>> auto fp = [] (int *x)
>>> ... so array length information is lost and range
>>> based for has no idea what range you mean.
>>>
>>>>
>>>
>> In the following program, the array definition and range based for
>> loop are in the same scope so it appears that the range based for loop
>> sees the size of the array.  The following program compiles with the
>> gnu compiler and runs correctly.  I am surprised that it works.
>> =========================================
>> #include <iostream>
>> #include <vector>
>> using namespace std;
>> int main(){
>>    int x[4] = {1, 2, 3, 4};
>>    int sum = 0;
>>    for(const int &i : x)
>>        sum += i;
>>    cout << "sum = " << sum << '\n';
>>    return 0;
>> }
> 
> Why are you surprised?
> 
> In `auto fp = [] (int x[])`, x is an array parameter, which is treated
> as a pointer parameter.  That equivalence applies only to function
> parameters.  In your example, you just have an array object.
> 
In the above program the x in the for loop is treated as
an int *. The fact that the program works means that the
for loop knows how far to increment the pointer to calculate
the sum.  This is what surprises me, I thought the only information
a built in array type contains is a pointer to the first element.

Thank you,
Joe

[toc] | [prev] | [next] | [standalone]


#88214

FromÖö Tiib <ootiib@hot.ee>
Date2022-12-22 00:00 -0800
Message-ID<e93558ce-937f-4e40-8a7a-a3a6d5ea6855n@googlegroups.com>
In reply to#88212
On Thursday, 22 December 2022 at 08:05:59 UTC+2, Joseph Hesse wrote:
> On 12/21/22 12:32, Keith Thompson wrote: 
> > Joseph Hesse <jo...@gmail.com> writes: 
> >> On 12/20/22 11:29, Öö Tiib wrote: 
> >>> auto fp = [] (int x[]) 
> >>> ... is by language rules equivalent to ... 
> >>> auto fp = [] (int *x) 
> >>> ... so array length information is lost and range 
> >>> based for has no idea what range you mean. 
> >>> 
> >>>> 
> >>> 
> >> In the following program, the array definition and range based for 
> >> loop are in the same scope so it appears that the range based for loop 
> >> sees the size of the array. The following program compiles with the 
> >> gnu compiler and runs correctly. I am surprised that it works. 
> >> ========================================= 
> >> #include <iostream> 
> >> #include <vector> 
> >> using namespace std; 
> >> int main(){ 
> >> int x[4] = {1, 2, 3, 4}; 
> >> int sum = 0; 
> >> for(const int &i : x) 
> >> sum += i; 
> >> cout << "sum = " << sum << '\n'; 
> >> return 0; 
> >> } 
> > 
> > Why are you surprised? 
> > 
> > In `auto fp = [] (int x[])`, x is an array parameter, which is treated 
> > as a pointer parameter. That equivalence applies only to function 
> > parameters. In your example, you just have an array object. 
> >
> In the above program the x in the for loop is treated as 
> an int *. The fact that the program works means that the 
> for loop knows how far to increment the pointer to calculate 
> the sum. This is what surprises me, I thought the only information 
> a built in array type contains is a pointer to the first element. 
> 
That is not true. The x in that program is int array of 4 elements,
not pointer. The array decays to pointer in lot of contexts but
range based for is not one of those. It treats x as an array.
<https://en.cppreference.com/w/cpp/language/range-for>

[toc] | [prev] | [next] | [standalone]


#88220

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2022-12-22 12:42 +0000
Message-ID<87lemzsj7e.fsf@bsb.me.uk>
In reply to#88214
Öö Tiib <ootiib@hot.ee> writes:

> On Thursday, 22 December 2022 at 08:05:59 UTC+2, Joseph Hesse wrote:
>> On 12/21/22 12:32, Keith Thompson wrote: 
>> > Joseph Hesse <jo...@gmail.com> writes: 
>> >> On 12/20/22 11:29, Öö Tiib wrote: 
>> >>> auto fp = [] (int x[]) 
>> >>> ... is by language rules equivalent to ... 
>> >>> auto fp = [] (int *x) 
>> >>> ... so array length information is lost and range 
>> >>> based for has no idea what range you mean. 
>> >>> 
>> >>>> 
>> >>> 
>> >> In the following program, the array definition and range based for 
>> >> loop are in the same scope so it appears that the range based for loop 
>> >> sees the size of the array. The following program compiles with the 
>> >> gnu compiler and runs correctly. I am surprised that it works. 
>> >> ========================================= 
>> >> #include <iostream> 
>> >> #include <vector> 
>> >> using namespace std; 
>> >> int main(){ 
>> >> int x[4] = {1, 2, 3, 4}; 
>> >> int sum = 0; 
>> >> for(const int &i : x) 
>> >> sum += i; 
>> >> cout << "sum = " << sum << '\n'; 
>> >> return 0; 
>> >> } 
>> > 
>> > Why are you surprised? 
>> > 
>> > In `auto fp = [] (int x[])`, x is an array parameter, which is treated 
>> > as a pointer parameter. That equivalence applies only to function 
>> > parameters. In your example, you just have an array object. 
>> >
>> In the above program the x in the for loop is treated as 
>> an int *. The fact that the program works means that the 
>> for loop knows how far to increment the pointer to calculate 
>> the sum. This is what surprises me, I thought the only information 
>> a built in array type contains is a pointer to the first element. 
>> 
> That is not true. The x in that program is int array of 4 elements,
> not pointer. The array decays to pointer in lot of contexts but
> range based for is not one of those. It treats x as an array.
> <https://en.cppreference.com/w/cpp/language/range-for>

You are right (of course!) but it's by no means trivial to follow the
details.  The cppreference page gives an example, but it's explanation
is very hard to plough through for someone learning C++.  You'd have to
understand how

  auto&& __range = x;

works and what __range and __range + 4 mean following a declaration like
that.

Clearly (at least I think so) __range will be an rvalue reference to an
array of 4 ints, but when I try to ditch the auto with

  int (&&__range)[4] = x;

g++ complains that it "cannot bind rvalue reference of type ‘int
(&&)[4]’ to lvalue of type ‘int [4]’.  What is the type that is being
deduced for __range in

  auto&& __range = x;

?  (Using a lvalue reference works but that's not what the standard says
is going on with this range-based for statement.)

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#88151

FromPaavo Helde <eesnimi@osa.pri.ee>
Date2022-12-20 20:03 +0200
Message-ID<tnstee$oct8$1@dont-email.me>
In reply to#88145
20.12.2022 19:00 Joseph Hesse kirjutas:
> I want to sum an array of int's in a lambda function.
> 
> In the following code, function f1 does this with no problem.
> 
> In function f2, I am able to sum an int array using a range based
> for loop.  That this works surprises me since the array name is not 
> converted to a pointer and the for loop "looks around" to find the
> size of int x[].
> 
> The commented out code in f2 was my attempt, as in f1, to
> put the code to sum the array in a lambda.  It does not compile.
> 
> Is it possible to make this work?
> 
> Thank you,
> Joe
> =======================================================
> #include <iostream>
> #include <vector>
> using namespace std;

> 
> void f2(){
>    int x[4] = {1, 2, 3, 4};
> 
>    int sum = 0;
>    for(const int &i : x)
>        sum += i;
>    cout << "sum = " << sum << '\n';
> 
> /*
>    auto fp = [] (int x[])
>    {
>      int sum = 0;
>      for(const int &i : x)
>        sum += i;
>      return sum;
>    };
> 
>    cout << "sum = " << fp(x) << '\n';
> */
> }

You can fix it easily by over-using auto:

void f2() {
     int x[4] = { 1, 2, 3, 4 };

     auto fp = [] (const auto& x)
       {
         int sum = 0;
         for(const int &i : x)
           sum += i;
         return sum;
       };

       std::cout << "sum = " << fp(x) << '\n';

}


However, using C arrays seems fragile in general as they decay to 
pointers too easily. This seems better:

void f2() {
     std::array<int, 4> x = { 1, 2, 3, 4 };

       auto fp = [] (const auto& range)
       {
         int sum = 0;
         for(const int &i : range)
           sum += i;
         return sum;
       };

       std::cout << "sum = " << fp(x) << '\n';

}







[toc] | [prev] | [next] | [standalone]


#88173

FromJuha Nieminen <nospam@thanks.invalid>
Date2022-12-21 06:35 +0000
Message-ID<tnu9f7$vn7$1@gioia.aioe.org>
In reply to#88145
Joseph Hesse <joeh@gmail.com> wrote:
>   auto fp = [] (vector<int> vi)

By the way, you should almost never take class instances like this
as function parameters by value. You should almost always take them
as const reference.

When you take it by value like that, it will be *copied* for the
function. The larger the vector is, the heavier it becomes to copy.
In most cases (like here) the function doesn't need a copy of the
vector. A reference to the original suffices (and passing a reference
as parameter to the function is infinitely more efficient than
copying the entire vector).

The only case where you want to pass such an object by value instead
of by reference is when the function actually needs a deep-copy of
the object, but that's quite rare. (Even in such cases it's actually
usually better to still take the parameter by const reference and
copy it inside the function.)

[toc] | [prev] | [next] | [standalone]


#88224

FromBonita Montero <Bonita.Montero@gmail.com>
Date2022-12-22 19:55 +0100
Message-ID<to295e$1ekd5$1@dont-email.me>
In reply to#88145
Am 20.12.2022 um 18:00 schrieb Joseph Hesse:

>    cout << "sum = " << fp(v) << '\n';

	cout << "sum = " << accumulate( v.cbegin(), v.cend() ) << endl;

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web