Pass function object to std algorithm by reference


Tomilov Anatoliy

Wouldn't it be better to pass functional objects into STL algorithms by forwarding references rather than by value? It will allow to take advantage of the reference qualifier of operator ()the passed function object .

There are several std::for_eachalgorithms about the problem SO( 1 , 2 ), which are problems with changes in the observable state passed to the function object std::for_each.

Even for algorithms that cannot return a function object (because they should return the last value of the output iterator or something), for those algorithms that cannot return a function object, passing the function object by lvalue reference solves the problem.

For example, the algorithm std::for_eachcan be changed to (copied from libc++):

template<typename _InputIterator, typename _Function>
_Function
for_each(_InputIterator __first, _InputIterator __last, _Function __f)
{
  for (; __first != __last; ++__first)
    __f(*__first);
  return _GLIBCXX_MOVE(__f);
}

to:

template<typename _InputIterator, typename _Function>
_Function &&
for_each(_InputIterator __first, _InputIterator __last, _Function && __f)
{
  for (; __first != __last; ++__first)
    _GLIBCXX_FORWARD(_Function, __f)(*__first);
  return _GLIBCXX_FORWARD(_Function, __f);
}

Or (if such breaking changes are allowed) std::for_eachcan go back voidwithout loss of functionality . Similar changes can be made std::forwardfor all the rest <numeric>and <algorithm>algorithms (from pass-by-value to pass-by-reference, and all calls to call -ed function objects, not just non-const-lvalues) .

I'm aware of a partial workaround: wrapping std::ref(or std::crefcoercing const this) the object around , but there is a problem with forwarding operator ()cv-ref-qualifiers from wrapped functional objects to wrapped objects operator ().

Another workaround is to explicitly specify the reference parameter type in the template parameter list of alorithm, but the current Functionparameter sadly always follows the InputIteratorsum parameter in the list OutputIterator:

#include <iostream>
#include <list>
#include <algorithm>
#include <iterator>
#include <utility>

#include <cstdlib>

int main()
{
    std::list< int > l{{1, 2, 3, 4}};
    std::copy_n(std::cbegin(l), l.size(), std::ostream_iterator< int >(std::cout, " "));
    std::cout << std::endl;
    struct F
    {
        int state;
        void operator () (int i) { state += i; }
    } f{0};
    using I = std::list< int >::const_iterator;
    std::for_each< I, F && >(std::cbegin(l), std::cend(l), std::move(f));
    std::cout << f.state << std::endl;
    return EXIT_SUCCESS;
}

By the way, the change will allow non-copyable and/or non-movable function objects to be passed to algorithms that don't wrap them.

Howard Sinnant

Wouldn't it be better to pass functional objects into STL algorithms by forwarding references rather than by value?

Yes, it would be better this way. It would be better if it was necessary to require that the functor does not have to be , or . But the standard clearly states in 25.1:CopyConstructibleCopyAssignableMoveConstructibleMoveAssignable

Note: Unless otherwise specified, algorithms that take function objects as arguments are allowed to copy those function objects freely. Programmers where object identity is important should consider using a wrapper class that points to an uncopied implementation object, such as reference_wrapper<T>(20.9.4) or some equivalent solution. — endnote ]

This issue was called LWG 92 back in 1998 . and added the "note me" referenced above at that time (this note was modified as it didn't exist at the time ).reference_wrapper<T>

This is a great solution for vendors of std::lib, and a great solution for committee members responsible for revising the spec, but for someone like you who wants to use stateful For functor people, this is not a good choice.

Of course, at the time there was no forwarding reference as a possible solution. Also at that time, it was common for std::implementation to pass functors by value in algorithms , which would further corrupt their state (as indicated by LWG 92 's specification) .

You have correctly touched all the points related to this question:

  • Clients could use std::refinstead , but this would not respect reference-qualified functors.

  • Clients can explicitly specify functor reference parameters, but this does not prohibit implementations from duplicating functors within an algorithm .

  • Explicitly specifying functor reference parameters is very inconvenient for the client because they always come last in the template parameter list.

First, libc++ is the only std::implementation written that forbids copying functors internally. That is, if you write an LWG 92 example:

#include <algorithm>
#include <iostream>
#include <list>
#include <numeric>

template <class C>
void
display(const C& c)
{
    std::cout << '{';
    if (!c.empty())
    {
        auto i = c.begin();
        std::cout << *i;
        for (++i; i != c.end(); ++i)
            std::cout << ", " << *i;
    }
    std::cout << '}' << '\n';
}

class Nth {    // function object that returns true for the nth element 
  private: 
    int nth;     // element to return true for 
    int count;   // element counter 
  public: 
    Nth (int n) : nth(n), count(0) { 
    } 
    bool operator() (int) { 
        return ++count == nth; 
    } 
};

int
main()
{
    std::list<int> coll(10);
    std::iota(coll.begin(), coll.end(), 0);
    display(coll);
    auto pos = std::remove_if(coll.begin(), coll.end(), Nth{3});
    coll.erase(pos, coll.end());
    display(coll);
}

The result today is:

libc ++

{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
{0, 1, 3, 4, 5, 6, 7, 8, 9}

g ++

{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
{0, 1, 3, 4, 6, 7, 8, 9}

VS-2015

{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
{0, 1, 3, 4, 6, 7, 8, 9}

g++'s libstdc++ and VS-2015 are stillNthInternal reproduction , remove_ifas described by Nico Josuttis 18 years ago.

Change the code to:

    Nth pred{3};
    auto pos = std::remove_if(coll.begin(), coll.end(), std::ref(pred));

does change the result to:

{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
{0, 1, 3, 4, 5, 6, 7, 8, 9}

IMHO it's just a runtime error waiting for programmers unfamiliar with std::lib's long history to do it.

Related


Pass function object to std algorithm by reference

Tomilov Anatoliy Wouldn't it be better to pass functional objects into STL algorithms by forwarding references rather than by value? It will allow to take advantage of the reference qualifier of operator ()the passed function object . There are several std::fo

Pass function object to std algorithm by reference

Tomilov Anatoliy Wouldn't it be better to pass functional objects into STL algorithms by forwarding references rather than by value? It will allow to take advantage of the reference qualifier of operator ()the passed function object . There are several std::fo

Pass function object to std algorithm by reference

Tomilov Anatoliy Wouldn't it be better to pass functional objects into STL algorithms by forwarding references rather than by value? It will allow to take advantage of the reference qualifier of operator ()the passed function object . There are several std::fo

Pass function object to std algorithm by reference

Tomilov Anatoliy Wouldn't it be better to pass functional objects into STL algorithms by forwarding references rather than by value? It will allow to take advantage of the reference qualifier of operator ()the passed function object . There are several std::fo

Pass a function object to std::function

no I'm having some trouble creating an instance of std::function using a function object. (My environment is C++11 with Visual Studio 2015.) First, I have a class that is used in the parameter list of a function object. This is a simplified version to illustra

Pass a function object to std::function

no I'm having some trouble creating an instance of std::function using a function object. (My environment is C++11 with Visual Studio 2015.) First, I have a class that is used in the parameter list of a function object. This is a simplified version to illustra

Pass a function object to std::function

No I'm having some trouble creating an instance of std::function using a function object. (My environment is C++11 with Visual Studio 2015.) First, I have a class that is used in the parameter list of a function object. This is a simplified version to illustra

Pass a function object to std::function

No I'm having some trouble creating an instance of std::function using a function object. (My environment is C++11 with Visual Studio 2015.) First, I have a class that is used in the parameter list of a function object. This is a simplified version to illustra

std::transform() pass reference in function parameter

Roy My question/concern is about the function parameter to be used in std::transform(). In the following code, if I use "pass by reference" in the integer parameter of ithe square function (ie int squared(int i)), it doesn't compile). I had to change it to pas

Pass anonymous function object to std::function?

Liang Tan Here is my problem: I define a functor: class A { public: int operator()(int a, int b) const{ return a + b; } }; typedef function<int (int, int)> Fun; Then I used an anonymous functor to create a std::function object and found somethin

Pass anonymous function object to std::function?

Liang Tan Here is my problem: I define a functor: class A { public: int operator()(int a, int b) const{ return a + b; } }; typedef function<int (int, int)> Fun; Then I used an anonymous functor to create a std::function object and found somethin

Pass anonymous function object to std::function?

Liang Tan Here is my problem: I define a functor: class A { public: int operator()(int a, int b) const{ return a + b; } }; typedef function<int (int, int)> Fun; Then I used an anonymous functor to create a std::function object and found somethin

Pass anonymous function object to std::function?

Liang Tan Here is my problem: I define a functor: class A { public: int operator()(int a, int b) const{ return a + b; } }; typedef function<int (int, int)> Fun; Then I used an anonymous functor to create a std::function object and found somethin

Pass anonymous function object to std::function?

Liang Tan Here is my problem: I define a functor: class A { public: int operator()(int a, int b) const{ return a + b; } }; typedef function<int (int, int)> Fun; Then I used an anonymous functor to create a std::function object and found somethin

Pass self-reference to function of containing object

1 cat duke I'm trying to use Rust's ownership model. I'm trying to pass a reference to the containing object when calling a function on a struct. Here is my structure: pub struct Player {} impl Player { pub fn receive(self, app: &App) { } } As you c

Pass function by reference, object with unexpected behavior

username So I have this code where I am trying to mutate the object by passing it as a reference to a function: var c = { why: 'older' }; var d; d = c; //passing by reference function changeGreeting(obj) { obj.why = 'newer' ; // mutate } changeGre

Pass self-reference to function of containing object

1 cat duke I'm trying to use Rust's ownership model. I'm trying to pass a reference to the containing object when calling a function on a struct. Here is my structure: pub struct Player {} impl Player { pub fn receive(self, app: &App) { } } As you c

Pass self-reference to function of containing object

cat duke I'm trying to use Rust's ownership model. I'm trying to pass a reference to the containing object when calling a function on a struct. Here is my structure: pub struct Player {} impl Player { pub fn receive(self, app: &App) { } } As you can

How to pass an object to a function by reference in C++?

Salem Alqahtani I am trying to compile my code by using make file. It seems to me that there is some problem with my code, but it doesn't have any errors except for the reference problem (referenced from :_main in lab2-f679eb.o). I am trying to pass an object

How to pass a reference to an object to a function for reuse

Lance McCarthy I'm trying to adhere to the DRY principle in my first Python application (I'm an experienced .NET developer). I've been able to move most of the repetitive code into reusable functions. For example, this is how I create lines (bounding boxes) fo

Pass self-reference to function of containing object

1 cat duke I'm trying to use Rust's ownership model. I'm trying to pass a reference to the containing object when calling a function on a struct. Here is my structure: pub struct Player {} impl Player { pub fn receive(self, app: &App) { } } As you c

Pass self-reference to function of containing object

1 cat duke I'm trying to use Rust's ownership model. I'm trying to pass a reference to the containing object when calling a function on a struct. Here is my structure: pub struct Player {} impl Player { pub fn receive(self, app: &App) { } } As you c

How to pass an object to a function by reference in C++?

Salem Alqahtani I am trying to compile my code by using make file. It seems to me that there is some problem with my code, but it doesn't have any errors except for the reference problem (referenced from :_main in lab2-f679eb.o). I am trying to pass an object

How to pass an object to a function by reference in C++?

Salem Alqahtani I am trying to compile my code by using make file. It seems to me that there is some problem with my code, but it doesn't have any errors except for the reference problem (referenced from :_main in lab2-f679eb.o). I am trying to pass an object

How to pass object to std::accumulate function?

world_of_science I am writing the code shown below. The goal of the code is to combine the different vectors into a single vector after concatenating elements from different vectors. The code below is incomplete and I can't find a way to pass the object sfrom