New algorithm std::transform_if

3,250 views
Skip to first unread message

vlad....@mail.ru

unread,
Jun 5, 2012, 3:56:59 PM6/5/12
to std-pr...@isocpp.org
I suggest to include in the C++ Standard new algorithm std::transform_if with the following declarations
 
template <class InputIterator, class OutputIterator,
                class UnaryPredicate, class UnaryOperation>
 
OutputIterator transform_if( InputIterator first, InputIterator last,
                                            OutputIterator result,
                                            UnaryPredicate pred, UnaryOperation op );
 
template <class InputIterator1, class InputIterator2, class OutputIterator,
class BinaryPredicate, class BinaryOperation>
OutputIterator transform_if( InputIterator1 first1, InputIterator1 last1,
                                            InputIterator first2, OutputIterator result,
                                            BinaryPredicate pred, BinaryOperation op );
 
There is a family of mutable conditional  algorithms as for example replace_if, remove_if and so on in the C++ Standard. In my opinion transform_if will append the family in naturally way.
 

Du Toit, Stefanus

unread,
Jun 5, 2012, 3:59:49 PM6/5/12
to std-pr...@isocpp.org

What are your proposed semantics for the new functions?

 

Thanks,

 

Stefanus

vlad....@mail.ru

unread,
Jun 5, 2012, 5:57:15 PM6/5/12
to std-pr...@isocpp.org
Assigning result a new value equal to op( *it ) or binary_op( *it1, *it2 ) where it in the range [first, last ) and it1 and it2 in the ranges [first1, last1) and [first2, first2 + ( last1 - first1 ) ) for which pred( *it ) or binary_pred( *it1, *it2 ) is true.
 
In fact they are the same as the corresponding std::transform algorithms but with an additional conditional predicate

вторник, 5 июня 2012 г., 23:59:49 UTC+4 пользователь Stefanus Du Toit написал:

Du Toit, Stefanus

unread,
Jun 6, 2012, 10:51:24 AM6/6/12
to std-pr...@isocpp.org

So, if I write something like:

 

std::array<int> a = {0, 1, 2, 3, 4};

std::transform_if(begin(a), end(a), std::ostream_iterator(std::cout, “ “), [](int i) -> bool { return i % 2 == 0; }, [](int i) -> int { return i * 2; })

 

Should the output be “0 1 4 3 8 ” or “0 4 8 ”?

 

(Please forgive any typos in the code, I did not try to compile it)

 

Thanks,

 

Stefanus

 

 

Sent: Tuesday, June 05, 2012 5:57 PM
To: std-pr...@isocpp.org

vlad....@mail.ru

unread,
Jun 6, 2012, 11:21:43 AM6/6/12
to std-pr...@isocpp.org
You an try it yourself
 
template <typename InputIterator, typename OutputIterator,
          typename UnaryPredicate, typename UnaryOperation>

OutputIterator transform_if( InputIterator first, InputIterator last,
                             OutputIterator result,
                             UnaryPredicate unary_predicate,
                             UnaryOperation unary_operation )
{
   for ( ; first != last ; ++first )
   {
      if ( unary_predicate( *first ) ) *result++ = unary_operation( *first );
   }
   return ( result );
}
среда, 6 июня 2012 г., 18:51:24 UTC+4 пользователь Stefanus Du Toit написал:

Du Toit, Stefanus

unread,
Jun 6, 2012, 11:47:16 AM6/6/12
to std-pr...@isocpp.org

Thanks, that makes it very clear (“0 4 8 “ would be my expectation below).

 

I think this would be a perfectly fine addition. Are there other algorithms where we are missing an _if version?

 

Stefanus

 

--

Stefanus Du Toit stefanus...@intel.com

  Intel Dynamic Mobility and Parallelism

  Intel Waterloo

  phone: +1 519 772 2576

vlad....@mail.ru

unread,
Jun 6, 2012, 1:00:42 PM6/6/12
to std-pr...@isocpp.org
I can suggest for example a who;e family of for_each algorithm.
 
for_each_if;
for_first;
for_first_if;
for_n;
for_n_if;
 
For example,
 
template <typename InputItterator,
                 typename T,
                 typename Function>
inline Function
for_first( InputIterator first, InputIterator last,
              const T &value, Function f )
{
   for ( ; first != last && *first == value ; ++first )
   {
      f( *first );
   }
 
   return ( f );
}
 

среда, 6 июня 2012 г., 19:47:16 UTC+4 пользователь Stefanus Du Toit написал:

Thanks, that makes it very clear (“0 4 8 “ would be my expectation below).

 

I think this would be a perfectly fine addition. Are there other algorithms where we are missing an _if version?

 

Stefanus

 

--

Stefanus Du Toit stefanus...@intel.com

  Intel Dynamic Mobility and Parallelism

  Intel Waterloo

  phone: +1 519 772 2576

 


среда, 6 июня 2012 г., 19:47:16 UTC+4 пользователь Stefanus Du Toit написал:
среда, 6 июня 2012 г., 19:47:16 UTC+4 пользователь Stefanus Du Toit написал:
среда, 6 июня 2012 г., 19:47:16 UTC+4 пользователь Stefanus Du Toit написал:

Marshall Clow

unread,
Jun 6, 2012, 1:11:56 PM6/6/12
to std-pr...@isocpp.org
On Jun 6, 2012, at 10:00 AM, vlad....@mail.ru wrote:

I can suggest for example a who;e family of for_each algorithm.
 
for_each_if;
for_first;
for_first_if;
for_n;
for_n_if;

Before we go down that road, I think that we should look at the range proposal; specifically filtered ranges.
If they are easy to use, and can generate good code, then I would argue against implementing a bunch of _if variants.

Instead of
for_each_if ( begin, end, pred, lambda )
you would write (day): for_each ( range(begin, end) | pred, lambda )

-- Marshall

P.S. The other half of this is that if we get "good ranges", we should take a hard look at deprecating some of the "_if" algorithms already in the standard library.
-- Marshall

Marshall Clow     Idio Software   <mailto:mclow...@gmail.com>

A.D. 1517: Martin Luther nails his 95 Theses to the church door and is promptly moderated down to (-1, Flamebait).
        -- Yu Suzuki

vlad....@mail.ru

unread,
Jun 6, 2012, 2:07:49 PM6/6/12
to std-pr...@isocpp.org
 
I think using for_each_if makes the symantic of code more clear. The function can be very compound moreover it can be a member of a class and to write a wrapper for it that to include a condition inside its body is not a very good idea. The function can be universal while conditions can be changed. So I think the function and the condition should be separated in for_each family of algorithms.
Let assume that we have some very compound function and want to apply it to some elements of a sequense which are equal to zero. Then we could write
 
for_each_if( s.begin(), s.end(), std::bind2nd( std::equal_to<T>(), 0 ), f );
 
This code is more clear than
 
std::for_each( s.begin(), s.end(), SomeWrapperWithUnclearAction );;
And if the condition will be changed then
std::for_each( s.begin(), s.end(), AnotherWrapperWithUnclearAction );;
 
for_each_if looks the following way
 
template <typename InputIterator, typename UnaryPredicate, typename Function>
 
inline Function 
for_each_if( InputIterator first, InputItterator last,
                     UnaryPredicate unary_predicate,
                     Function f )
{
   for ( ; first != last ; ++first )
   {
      if ( unary_predicate( *first ) ) f( *first );
   }
 
   return ( f );
}
 
for_first_if:
 
template <typename InputIterator, typename UnaryPredicate, typename Function>
 
inline Function
for_first_if( InputIterator first, InputIterator last,
                  UnaryPredicate unary_predicate,
                  Function f )
{
   for ( ; first != last && unary_predicate( *first ) ; ++first )
   {
      f( *first );
   }
 
   return ( f );
}
 
Algorithm for_n is similar to std::copy_n
 
template <typename ForwardIterator, typename Size, typename Function>
inline Function
for_n( ForwardIterator first, Size n, Function f )
{
   for ( ; n != 0 ; --n, ++first ) f( *first );
 
   return ( f );
}
 
first_n_if:
 
template <typename ForwardIterator, typename Size,
                 typename UnaryPredicate, typename Function>
 
inline Function
for_n_if( ForwardIterator first, Size n,
               UnaryPredicate unary_predicate, Function f )
{
   for ( ; n != 0 ; --n, ++first )
   {
      if ( unary_predicate( *first ) ) f( *first );
   }
 
   return ( f );
}
  
среда, 6 июня 2012 г., 21:11:56 UTC+4 пользователь Marshall написал:

Jeffrey Yasskin

unread,
Jun 6, 2012, 2:18:48 PM6/6/12
to std-pr...@isocpp.org
On Wed, Jun 6, 2012 at 11:07 AM, <vlad....@mail.ru> wrote:
>
> I think using for_each_if makes the symantic of code more clear. The
> function can be very compound moreover it can be a member of a class and to
> write a wrapper for it that to include a condition inside its body is not a
> very good idea. The function can be universal while conditions can be
> changed. So I think the function and the condition should be separated in
> for_each family of algorithms.
> Let assume that we have some very compound function and want to apply it to
> some elements of a sequense which are equal to zero. Then we could write
>
> for_each_if( s.begin(), s.end(), std::bind2nd( std::equal_to<T>(), 0 ), f );

2¢: Use a lambda instead of bind2nd if you're writing C++11 or
proposing C++17 code. You'll find it makes the code much clearer, and
may change many of your opinions about library design.

Jeffrey

Nevin Liber

unread,
Jun 6, 2012, 2:23:57 PM6/6/12
to std-pr...@isocpp.org
endOn 6 June 2012 13:07, <vlad....@mail.ru> wrote:
 
I think using for_each_if makes the symantic of code more clear. The function can be very compound moreover it can be a member of a class and to write a wrapper for it that to include a condition inside its body is not a very good idea. The function can be universal while conditions can be changed. So I think the function and the condition should be separated in for_each family of algorithms.
Let assume that we have some very compound function and want to apply it to some elements of a sequense which are equal to zero. Then we could write
 
for_each_if( s.begin(), s.end(), std::bind2nd( std::equal_to<T>(), 0 ), f );
 
This code is more clear than
 
std::for_each( s.begin(), s.end(), SomeWrapperWithUnclearAction );;
And if the condition will be changed then
std::for_each( s.begin(), s.end(), AnotherWrapperWithUnclearAction );;

Sure, but in C++11, I'd write it as:

for_each(begin(s), end(s), [&](decltype(*end(s)) t) { if (v == 0) f(v); });

(and it gets even nicer with polymorphic lambdas at least in theory.)

Now that we have lambdas, I'm not seeing the motivating case for for_each_if.
--
 Nevin ":-)" Liber  <mailto:ne...@eviloverlord.com(847) 691-1404

Marshall Clow

unread,
Jun 6, 2012, 2:32:54 PM6/6/12
to std-pr...@isocpp.org
And given filtered ranges, I like this even better (uncompiled code):
for_each ( range(begin, end) | bool [&] (decltype(*end(s)) t) { return v == 0; }, f );

In this example, the win of filtered ranges doesn't show through that well, but think about stringing filters together:
for_each ( range | filter1 | filter2, f );

would apply the functor 'f' to every element of the range that matched both predicates.

That's really awkward using either a lambda or for_each_if (and even more awkward with three predicates)

vlad....@mail.ru

unread,
Jun 6, 2012, 2:42:45 PM6/6/12
to std-pr...@isocpp.org
The problem is that there are cases that sometimes it is more convenient do not use a lambda expression. A condition can be compound and it is difficult to read such lambda expressions. For example let consider the following condition: a row of a two dimensional array does not contain negative elements. Then it could be writtten separatly
 
auto non_negative =
   [] ( decltype( *std::begin( a ) ) &x )
   {
      return ( std::none_of( std::begin( x ), std::end( x ),
                   std::bimd2nd( std::less<int>(), 0 ) ) );
   };
 
Another object to calculate a product of all elements of row
 
auto product =
   [] ( decltype( *std::begin( a ) ) &x )
   {
      return ( std::accumulate( std::begin( x ), std::end( x ), 1,
                                              std::multiplies<int>() ) );
   };
 
Now we can print out products off elements of all rows which do not contain negative elements of a two dimensional matrix
 
transform_if( std::begin( a ), std::end( a ),
                     std::ostream_iterator<int>( std::cout, " " ),
                     non_negative, product );
 
So lambda expressions can be joined with i'if' algorithms. 

среда, 6 июня 2012 г., 22:23:57 UTC+4 пользователь Nevin ":-)" Liber написал:

Marshall Clow

unread,
Jun 6, 2012, 2:51:24 PM6/6/12
to std-pr...@isocpp.org

On Jun 6, 2012, at 11:42 AM, vlad....@mail.ru wrote:

> The problem is that there are cases that sometimes it is more convenient do not use a lambda expression. A condition can be compound and it is difficult to read such lambda expressions. For example let consider the following condition: a row of a two dimensional array does not contain negative elements. Then it could be writtten separatly
>
> auto non_negative =
> [] ( decltype( *std::begin( a ) ) &x )
> {
> return ( std::none_of( std::begin( x ), std::end( x ),
> std::bimd2nd( std::less<int>(), 0 ) ) );
> };
>
> Another object to calculate a product of all elements of row
>
> auto product =
> [] ( decltype( *std::begin( a ) ) &x )
> {
> return ( std::accumulate( std::begin( x ), std::end( x ), 1,
> std::multiplies<int>() ) );
> };
>
> Now we can print out products off elements of all rows which do not contain negative elements of a two dimensional matrix
>
> transform_if( std::begin( a ), std::end( a ),
> std::ostream_iterator<int>( std::cout, " " ),
> non_negative, product );

Or (if I understand your example):
transform ( range (begin, end ) | non_negative, std::ostream_iterator<int>( std::cout, " " ), product );

vlad....@mail.ru

unread,
Jun 6, 2012, 2:56:28 PM6/6/12
to std-pr...@isocpp.org
It is a student assignment: print out products of elements of all rows that do not contain negative values of a two-dimensional array (matrix ).
If to write it in one line with lambda expressions it will be difficult to read the code.
 
среда, 6 июня 2012 г., 22:51:24 UTC+4 пользователь Marshall написал:

vlad....@mail.ru

unread,
Jun 6, 2012, 5:10:27 PM6/6/12
to std-pr...@isocpp.org
There is one problem with the code
 
for_each(begin(s), end(s), [&](decltype(*end(s)) t) { if (v == 0) f(v); });
 
What does for_each return? I would like to get f without the condition. Separating the condition and the operation allows to return the operation and use it in another algorithm.
 

среда, 6 июня 2012 г., 22:23:57 UTC+4 пользователь Nevin ":-)" Liber написал:
endOn 6 June 2012 13:07, <vlad....@mail.ru> wrote:

Nevin Liber

unread,
Jun 6, 2012, 5:38:32 PM6/6/12
to std-pr...@isocpp.org
On 6 June 2012 16:10, <vlad....@mail.ru> wrote:
There is one problem with the code
 
for_each(begin(s), end(s), [&](decltype(*end(s)) t) { if (v == 0) f(v); });
 
What does for_each return? I would like to get f without the condition. Separating the condition and the operation allows to return the operation and use it in another algorithm.

I don't have to return it; [&] captures it into the lambda by reference.

In general, you don't know how many times an algorithm might copy your function object.  From n3290 25.1p10

[ Note: Unless otherwise specified, algorithms that take function objects as arguments are permitted to copy
those function objects freely. Programmers for whom object identity is important should consider using a
wrapper class that points to a noncopied implementation object such as reference_wrapper<T> (20.8.3),
or some equivalent solution. —end note ]

How do you solve that problem now?

My C++03 solution tended to use pimpl so the user didn't have use reference_wrapper to get it right.

I've found that with lambdas things such as multiplies, bind, ostream_iterator, etc., are needed far less often, as I can directly express my intent in the code at the point of call.  Ranges will give me even better expressiveness.
__

Alisdair Meredith

unread,
Jun 6, 2012, 5:46:55 PM6/6/12
to std-pr...@isocpp.org
My preference would be to make writing filtering iterators much simpler, possibly providing a filter iterator adapter in the library.  This is a far more composable solution than adding an '_if' variant of every known algorithm.

That said, we already have a wide range of '_if' algorithms, and just for consistency, it might be worth completing the set - although it sets an unfortunate precedent if we get an inundation of new algorithms at some point in the future.

I think it would help evaluate desirability if we had a list of all the current '_if' algorithms by name, and another list of those we should add to complete the set.

I don't plan on writing those lists from my phone ;)

AlisdairM

Sent from my iPhone

Marshall Clow

unread,
Jun 6, 2012, 8:30:47 PM6/6/12
to std-pr...@isocpp.org
On Jun 6, 2012, at 2:46 PM, Alisdair Meredith wrote:

> My preference would be to make writing filtering iterators much simpler, possibly providing a filter iterator adapter in the library. This is a far more composable solution than adding an '_if' variant of every known algorithm.
>
> That said, we already have a wide range of '_if' algorithms, and just for consistency, it might be worth completing the set - although it sets an unfortunate precedent if we get an inundation of new algorithms at some point in the future.
>
> I think it would help evaluate desirability if we had a list of all the current '_if' algorithms by name, and another list of those we should add to complete the set.

It's a smaller list than you think.

A quick grep through the standard and a set of header files for "_if" turns up
(besides innumerable "enable_if" and "basic_ifstream", etc)

find_if
find_if_not

count_if

copy_if

remove_if
remove_copy_if

replace_if
replace_copy_if

vlad....@mail.ru

unread,
Jun 6, 2012, 8:37:58 PM6/6/12
to std-pr...@isocpp.org
As for me I would append the liist at least with
 
for_each_if
transform_if
reverse_if

четверг, 7 июня 2012 г., 4:30:47 UTC+4 пользователь Marshall написал:

vlad....@mail.ru

unread,
Jun 6, 2012, 8:39:08 PM6/6/12
to std-pr...@isocpp.org
I have forgot reverse_copy_if :)

четверг, 7 июня 2012 г., 4:37:58 UTC+4 пользователь (неизвестно) написал:

vlad....@mail.ru

unread,
Jun 6, 2012, 9:10:17 PM6/6/12
to std-pr...@isocpp.org
I would say even that reverse_copy_if shall be because together with reverse_copy they are logical supplement correspondignly to  copy_if and copy.

четверг, 7 июня 2012 г., 4:39:08 UTC+4 пользователь (неизвестно) написал:

Marshall Clow

unread,
Jun 6, 2012, 9:21:28 PM6/6/12
to std-pr...@isocpp.org

On Jun 6, 2012, at 2:46 PM, Alisdair Meredith wrote:

> My preference would be to make writing filtering iterators much simpler, possibly providing a filter iterator adapter in the library. This is a far more composable solution than adding an '_if' variant of every known algorithm.
>
> That said, we already have a wide range of '_if' algorithms, and just for consistency, it might be worth completing the set - although it sets an unfortunate precedent if we get an inundation of new algorithms at some point in the future.
>
> I think it would help evaluate desirability if we had a list of all the current '_if' algorithms by name, and another list of those we should add to complete the set.
>

Ok, let's start with some notation - so we're all on the same page.

Basic concepts
[ begin, end ) - define a range
range - also defines a range
end (range) is the same as end
begin (range) is the same as begin
is_empty ( range ) - a synonym for begin ( range ) == end ( range )

Range adapters:
range | pred - defines a new range; all the members of "range" that satisfy "pred"
range | !pred - defines a new range; all the members of "range" that do not satisfy "pred"
reverse ( range ) - defines a new range; all the members of range, but they get traversed in the reverse order.
this is different than std::reverse, which moves elements around.
So - what have we got?

find_if (begin, end, pred)
--> begin (range | pred) // retrieve the first element of the filtered range

find_if_not (begin, end, pred)
--> begin (range | !pred) // retrieve the first element of the filtered range

count_if (begin, end, pred)
--> count (range | pred)

copy_if (begin, end, out, pred)
--> copy (range | pred, out)

remove_if (begin, end, pred)
// I don't think you can't do this with filtered ranges

remove_copy_if (begin, end, pred)
// I don't think you can't do this with filtered ranges

replace_if (begin, end, pred, new_value)
--> replace (range | pred, new_value)

replace_copy_if (begin, end, out, pred)
// I don't think you can't do this with filtered ranges

and some other ones:
reverse_copy ( begin, end, out )
--> copy ( reverse (range), out )

all_of ( begin, end, pred )
--> is_empty ( range | !pred )

none_of ( begin, end, pred )
--> is_empty ( range | pred )

## Now for Vlad's suggestions:

for_each_if ( begin, end, pred, func)
--> for_each ( range | pred, func )

transform_if ( begin, end, pred, out, op )
--> transform ( range | pred, out, op )

reverse_if // I'm not quite sure what reverse_if should do...

reverse_copy_if ( begin, end, pred, out )
--> copy ( reverse ( range | pred ), out )


Notes:
* I'm talking about syntax here; I make no claims about implementations
* replacing find_if with begin ( range | pred ) does not make for clearer code, IMHO
* I think there's more interesting algorithms here that we can compose from these primitives.

vlad....@mail.ru

unread,
Jun 7, 2012, 7:42:08 AM6/7/12
to std-pr...@isocpp.org
Also I would llike that algorithms for_first and for_first_if would be taken into acccount because they have no a substitution.
 

Ville Voutilainen

unread,
Jun 7, 2012, 7:56:11 AM6/7/12
to std-pr...@isocpp.org
On 7 June 2012 14:42, <vlad....@mail.ru> wrote:
>> Also I would llike that algorithms for_first and for_first_if would be
>> taken into acccount because they have no a substitution.

They have no substitution? I guess they do, but the substitutions are
not as convenient
as for_first and for_first_if would be, right? Do we want to have
copy_first? transform_first?
accumulate_first? And their first_if counterparts?

Dave Abrahams

unread,
Jun 7, 2012, 8:08:24 AM6/7/12
to std-pr...@isocpp.org
Speaking personally, I can't remember how to understand all these
combinations of qualifiers on algorithm names, I don't think it's
scalable (an NxM problem waiting to happen if it hasn't happened
already), and I would far prefer a system that lets algorithmic
properties be combined algebraically (along the general lines of what
Boost.Range does).

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

Ville Voutilainen

unread,
Jun 7, 2012, 8:16:17 AM6/7/12
to std-pr...@isocpp.org
On 7 June 2012 15:08, Dave Abrahams <da...@boostpro.com> wrote:
>> as for_first and for_first_if would be, right? Do we want to have
>> copy_first? transform_first?
> Speaking personally, I can't remember how to understand all these
> combinations of qualifiers on algorithm names, I don't think it's
> scalable (an NxM problem waiting to happen if it hasn't happened
> already), and I would far prefer a system that lets algorithmic
> properties be combined algebraically (along the general lines of what
> Boost.Range does).

I think we are in violent agreement. The proliferation of various combinations
seems unwise, I'd prefer something a bit more generic, and a filtered range
combined with a for_each/transform/others seems more general and
scalable to me than adding
for_first_if and its 10 merry friends would. ;)

vlad....@mail.ru

unread,
Jun 7, 2012, 8:18:27 AM6/7/12
to std-pr...@isocpp.org
I meant that there is no algorithm that is a direct substitution for for_first and for_first_if.
 
As for copy_first and copy_first_if I think that they also could be included. This set of algorithms is more complete and consistent.
 
As for algorithms from <numeric> I would not touch them. The only think I am not satisfied is the return type of iota. In my opinion all such algorithms as iota, fill and some others shall return the last iterator of the processed range.
  
Четверг, 7 июня 2012 г., 15:56:11 UTC+4 пользователь Ville Voutilainen написал:
четверг, 7 июня 2012 г., 15:56:11 UTC+4 пользователь Ville Voutilainen написал:
четверг, 7 июня 2012 г., 15:56:11 UTC+4 пользователь Ville Voutilainen написал:

vlad....@mail.ru

unread,
Jun 7, 2012, 8:28:26 AM6/7/12
to std-pr...@isocpp.org

For example I do not remember all functions from standard C hheader <cstring>. However when I see a function from this library in a code I know what it is used for.
The same is valid for algorithms. When I will see for example for_first_if  I will know what it is used for. It will be more difficult to understand what an algorithm is doing considering its compound set of arguments.

Ville Voutilainen

unread,
Jun 7, 2012, 8:53:04 AM6/7/12
to std-pr...@isocpp.org
On 7 June 2012 15:28, <vlad....@mail.ru> wrote:
> The same is valid for algorithms. When I will see for example for_first_if
> I will know what it is used for. It will be more difficult to understand
> what an algorithm is doing considering its compound set of arguments.

That's a quite reasonable counterargument, generic composition can
get quite messy. Providing shortcuts to common things is reasonable,
but we need to consider where to draw the line. It's still relatively easy to
write shortcuts implemented with generic composition (just write
a function that's implemented with generic composition), but it's
downright impossible
to generalize from the shortcuts. That indicates to me that the more
important facility would be having the generic composition, and the
shortcuts are somewhat nice-to-haves.

Jeremiah Willcock

unread,
Jun 7, 2012, 10:06:34 AM6/7/12
to std-pr...@isocpp.org
In addition to some kind of range adaptor interface, would it make sense
to have language-level sequence comprehensions (like list comprehensions
but returning ranges)? Oven has a library-based syntax, but would people
want a language version? These are the kinds of features that I had in
mind:
http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/syntax-extns.html#generalised-list-comprehensions

-- Jeremiah Willcock

Dave Abrahams

unread,
Jun 7, 2012, 10:48:38 AM6/7/12
to std-pr...@isocpp.org

on Wed Jun 06 2012, Marshall Clow <mclow.lists-AT-gmail.com> wrote:

> * I'm talking about syntax here; I make no claims about implementations

I was assuming your "syntax" was just a notational shorthand, so I
wasn't going to say anything, but... I'm fairly certain !pred is never
going to fly, because it requires an exotic definition of "predicate"
that supports a special operator! semantics.

Dave Abrahams

unread,
Jun 7, 2012, 10:55:50 AM6/7/12
to std-pr...@isocpp.org
Yes, please; I use them all the time in Python. I would be just as
happy to have a library solution if it could have a nice syntax, but I
don't think what I see at
http://p-stade.sourceforge.net/oven/doc/html/oven/ranges.html#oven.ranges.comprehension
cuts the mustard.

trying-to-resist-baking-puns-ly y'rs,

vlad....@mail.ru

unread,
Jun 7, 2012, 12:51:55 PM6/7/12
to std-pr...@isocpp.org
In my opinion it is incorrect approach that if range adaptors will be adopted the set of standard algorithms should not be changed. I think that the range adapters are only one of possibilities. I am sure that despite of existense of range adapters many programmers will use for example for_first_if because it is simpler, clear, more effective and does not require piling up many constructions. The set of algorithms should be complete, consistent and sutisfy  many requirements of users.
 

user...@yahoo.com

unread,
Jun 8, 2012, 5:34:27 AM6/8/12
to std-pr...@isocpp.org
On Thursday, June 7, 2012 5:51:55 PM UTC+1, (unknown) wrote:
I am sure that despite of existense of range adapters many programmers will use for example for_first_if because it is simpler, clear, more effective and does not require piling up many constructions. The set of algorithms should be complete, consistent and sutisfy  many requirements of users.
 
I am sure that the vast majority of C++ programmers use only non-trivial standard algorithms like std::sort or do not use standard algorithms at all. The most useful library components are those which are widely used and those which implement non-trivial functionality. I believe that we have much more serious problems than the lack of for_first_if. For example, it's a real shame that in 2012 we can't pass a filename consisting of wide characters to std::fstream.

vlad....@mail.ru

unread,
Jun 8, 2012, 7:34:23 AM6/8/12
to std-pr...@isocpp.org

пятница, 8 июня 2012 г., 13:34:27 UTC+4 пользователь (неизвестно) написал:
On Thursday, June 7, 2012 5:51:55 PM UTC+1, (unknown) wrote:
I am sure that despite of existense of range adapters many programmers will use for example for_first_if because it is simpler, clear, more effective and does not require piling up many constructions. The set of algorithms should be complete, consistent and sutisfy  many requirements of users.
 
I am sure that the vast majority of C++ programmers use only non-trivial standard algorithms like std::sort or do not use standard algorithms at all. The most useful library components are those which are widely used and those which implement non-trivial functionality. I believe that we have much more serious problems than the lack of for_first_if. For example, it's a real shame that in 2012 we can't pass a filename consisting of wide characters to std::fstream.
 
Well. then please make a proposal to exclude from the Standard the following algorithms as for_each, copy, copy_if, copy_backward, find, find_if and so on because thay  are  all trivial. :)
I understand that you are busy by solving global problems but from my point of view the Standard shall have a complete and consistent set of functions even if they are trivial.  It is very seriious question. Also I am sure this will not  prevent you from solving your global problems.:)

Ville Voutilainen

unread,
Jun 8, 2012, 7:42:58 AM6/8/12
to std-pr...@isocpp.org
On 8 June 2012 14:34, <vlad....@mail.ru> wrote:
> I understand that you are busy by solving global problems but from my point
> of view the Standard shall have a complete and consistent set of functions
> even if they are trivial.  It is very seriious question. Also I am sure this
> will not  prevent you from solving your global problems.:)

Vlad, would you be interested in authoring a proposal paper? That would get
the ball rolling. To me, the missing _if algorithms are relatively easy, I
expect the _first and _first if algorithms to raise some discussion, but
your point about a complete and consistent set is a good one.

vlad....@mail.ru

unread,
Jun 8, 2012, 8:03:18 AM6/8/12
to std-pr...@isocpp.org

пятница, 8 июня 2012 г., 15:42:58 UTC+4 пользователь Ville Voutilainen написал:
Ville, thanks for the suggestion. However I have no expirience in performing such work. If I would  take upon myself this task it would be required no less than a month or even two months (or the whole summer:) ).  But I think it is not a very urgent problem, is not it? So there will be enough time to prepare the proposal, will not be? If so I could try.  

Ville Voutilainen

unread,
Jun 8, 2012, 8:38:16 AM6/8/12
to std-pr...@isocpp.org
On 8 June 2012 15:03, <vlad....@mail.ru> wrote:
> Ville, thanks for the suggestion. However I have no expirience in performing
> such work. If I would  take upon myself this task it would be required no

Take an existing paper as a base. You need to provide the rationale, and if
you can, the wording. It's not as daunting as it may seem. :) I can help
you along, and so can people like Daniel, although I can't promise timeslices
from him. ;)

Daniel Krügler

unread,
Jun 8, 2012, 8:45:53 AM6/8/12
to std-pr...@isocpp.org
2012/6/8 Ville Voutilainen <ville.vo...@gmail.com>:
Yes, Ville's description is basically all you need.

I expect this paper to be simple, so don't hesitate to contact me directly,
if there are any further questions.

- Daniel

Ville Voutilainen

unread,
Jun 8, 2012, 8:56:11 AM6/8/12
to std-pr...@isocpp.org
On 8 June 2012 15:45, Daniel Krügler <daniel....@googlemail.com> wrote:
>> Take an existing paper as a base. You need to provide the rationale, and if
>> you can, the wording. It's not as daunting as it may seem. :) I can help
>> you along, and so can people like Daniel, although I can't promise timeslices
>> from him. ;)
> Yes, Ville's description is basically all you need.
> I expect this paper to be simple, so don't hesitate to contact me directly,
> if there are any further questions.

Some suggestions:

1) the obvious, propose transform_if
2) cover missing _if algorithms
3) add the _first/_first_if algorithms where it makes sense,
make that a separate part of the paper. It could be split out into
a separate proposal, but that's not a stringent requirement
4) observe the discussions, bring popcorn
5) enjoy a new improved standard
6) ??
7) profit!

;)

user...@yahoo.com

unread,
Jun 8, 2012, 11:19:23 AM6/8/12
to std-pr...@isocpp.org
On Friday, June 8, 2012 12:34:23 PM UTC+1, (unknown) wrote:
I am sure that the vast majority of C++ programmers use only non-trivial standard algorithms like std::sort or do not use standard algorithms at all. The most useful library components are those which are widely used and those which implement non-trivial functionality. I believe that we have much more serious problems than the lack of for_first_if. For example, it's a real shame that in 2012 we can't pass a filename consisting of wide characters to std::fstream.
 
Well. then please make a proposal to exclude from the Standard the following algorithms as for_each, copy, copy_if, copy_backward, find, find_if and so on

That would break backward compatibility.
 
because thay  are  all trivial. :)

They are not as trivial as you could think of.
 
I understand that you are busy by solving global problems but from my point of view the Standard shall have a complete and consistent set of functions even if they are trivial.

How many pages of the standard should describe your complete and consistent set of functions? 500? 1000? or maybe 10000? Don't forget that the standard library is intended to provide basic commonly used functionality. It's not supposed to include everything that might be useful.

vlad....@mail.ru

unread,
Jun 8, 2012, 11:45:03 AM6/8/12
to std-pr...@isocpp.org

пятница, 8 июня 2012 г., 19:19:23 UTC+4 пользователь Kevin Pirrelli написал:
Very good! The same words as yours "They are not as trivial as you could think of" I can say you!:)
If you would start your arguments with this words all other words for example about the number of pages were unimportant.:)  
 
Spend your energy on your own proposals that you think are very important for the evoluation of C++. And do not bother about the number of pages of C++ description.

Alisdair Meredith

unread,
Jun 9, 2012, 6:48:41 AM6/9/12
to std-pr...@isocpp.org
There are many ways the standard may be improved, in both large ways and small ways.

For example, we now have Study Group 3 looking to produce a library addressing the needs
of navigating a file system, which will address the need for wide-character file names.

This does not preclude working on improving the library or standard document in many
other small ways, and this forum is intended to support all such discussion. The standard
improves by motivated people writing up proposals for the committee to consider, and
people will generally work on the issues that concern them - it is rarely a matter of
trading off one topic for another - if we say 'this is not important, work on something
else', the risk is that we entirely lose someone who was interested in working on a
better standard instead.

When we are so inundated with proposals that we cannot address them all, then
we might start postponing work based on priorities at the time - it is a problem
that I would love to have, but we are not there yet! In the meantime, I would
like to encourage anyone motivated to write a proposal to do so.

And yes, especially proposals solving some of more notable gaps in the library!

AlisdairM

Alisdair Meredith

unread,
Jun 9, 2012, 7:00:31 AM6/9/12
to std-pr...@isocpp.org
One of the reasons this forums was set up was to encourage new
contributors to write proposals!

Formal proposals are essential to the way the committee does its
work - until an idea is written up and distributed in a committee
mailing, it does not not get on our agenda, and will not have an
impact on the standard.

The deadline for submissions to the next mailing is mid-September
so there is plenty of time to write a proposal. From the number of
messages on this forum, I would say there is definitely sufficient
interest to warrant a paper, and people motivated to help you
write it.

Such a paper should consist of:
1. a brief introduction describing the problem to be solved
2. the list of algorithms you are proposing, and the criteria
used to select them
3. a quick description of each algorithm
4. wording for proposed changes to the standard.


Part (3) may be optional, if the specification in (4) will be
so clear that you think it can be safely omitted.

(4) is the fun part for a first proposal, as it can feel daunting
but is also quite satisfying to complete. In this case, it is
relatively simple, as the majority of your standard wording
can be produced by copy/pasting from the specification of
existing, similar algorithms.

AlisdairM

vlad....@mail.ru

unread,
Jun 9, 2012, 7:28:45 AM6/9/12
to std-pr...@isocpp.org
Well, I will try though it is a big work, because I am going to touch many algorithms. It is a good opportunity to make this part of the Standard such a way as i would like it would be.:)
 
During writing I will show my proposals here for each algorithm I am going to change and I will ask how some task can be done.
.
For example how to reverse values of the mapped_type in std::map?
 
In my opinion it could be done with the following algorithm
 
template <typename BidirectionalIterator, typename BinaryPredicate>
void reverse( BidirectionalIterator first, BidirectionalIterator last,
                      BinaryPredicate binary_predicate );

So the reverse will have at least four modifications:
 
1. std::reverse
2. std::reverse with binary predicate
2. std::reverse_if
3. std:;reverse_if with binary predicate
 
And all these changes require discussions because I can be wrong.
 

суббота, 9 июня 2012 г., 15:00:31 UTC+4 пользователь Alisdair Meredith написал:
Reply all
Reply to author
Forward
0 new messages