anthony sottile
anthony sottile

Reputation: 70223

Function pointer to friend operator overload for use with bind

The end goal is the following: I want to be able to use for_each with operator<<. I realized I can just use ostream_iterator but I would like to see if it is possible without it.

Some example code so you can get an idea of what I want to do:

#include <algorithm>
#include <iostream>
#include <functional>
#include <vector>

using std::bind;
using std::ref;
using std::placeholders::_1;
using std::for_each;
using std::ostream;
using std::cout;
using std::endl;
using std::vector;

class C {
    private:
        int x;
    public:
        C() : x(0) { }
        C(int x) : x(x) { }

    friend ostream& operator<<(ostream& out, const C& c);
};

ostream& operator<<(ostream& out, const C& c) {
    return out << c.x << endl;
}

int main() {
    vector<C> v;
    v.push_back(C(1));
    v.push_back(C());

    for_each(v.begin(), v.end(), bind(&ostream::operator<<, ref(cout), _1));

    return 0;
}

A thing I have unsuccessfully tried (above):

bind(static_cast<ostream& (ostream::*)(ostream&, const C&)>(&ostream::operator<<), ref(cout), _1)

Upvotes: 0

Views: 548

Answers (3)

qPCR4vir
qPCR4vir

Reputation: 3571

Is here any problem?

for (auto c :v) cout<<c;

or here:

for (const auto& c :v) cout<<c;

or here:

for (C const& c :v) cout<<c;

Upvotes: 1

ecatmur
ecatmur

Reputation: 157484

You're specifying the wrong operator<<; you've specified ostream::operator<<, but your operator<< is free i.e. ::operator<<.

This works in your current program:

for_each(v.begin(), v.end(), bind(&::operator<<, ref(cout), _1));

However if you add any more free operator<<s then it will fail again, since bind cannot decide which operator<< is meant. In that case you would have to specify through an explicit specialization:

for_each(v.begin(), v.end(), bind<ostream&(*)(ostream&, const C&)>(&::operator<<, ref(cout), _1));

Equivalently, you could use static_cast<ostream&(*)(ostream&, const C&)>(&::operator<<).

The problem is that the << in std::cout << c could be either a free operator or a member operator, and there's no way to know which a priori. ostream_iterator works by generating code that allows the compiler to decide how to evaluate the expression; similarly if you use a lambda or just a range for loop.

Upvotes: 3

Nevin
Nevin

Reputation: 4863

You can just use a lambda, as in:

for_each(v.begin(), v.end(), [](C const& c){ cout << c; });

Personally, I prefer to use for_each when my intention is to visit every element in the sequence.

Upvotes: 3

Related Questions