5 Replies - 7179 Views - Last Post: 03 October 2010 - 02:47 AM Rate Topic: -----

#1 code_m  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 24
  • View blog
  • Posts: 202
  • Joined: 21-April 09

Using a member function with the STL

Posted 01 October 2010 - 09:49 PM

Ok, so in school I've come accross a situation where I need to quick dump items back into a container that does not have iterators. Namely the priority_queue. Here's the way I have been doing it:

struct mv_back {
private:
    priority_queue<int>* pq;

public:
    mv_back(priority_queue<int>* pq) : pq(pq) { }
    ~mv_back(void) { this->pq = NULL; }

    void operater()(int& n) {
        pq->push(n);
    }
};

int main(int argc, char** argv) {
    priority_queue<int> pq;

    // fill up pq

    vector<int> v;

    while (! pq.empty() && pq.top() > 5) {
        v.push_back(pq.top());
        pq.pop();
    }

    for_each(v.begin(), v.end(), mv_back(&pq));

    return 0;
}



The line I really care about is the for_each, I would much rather just do:
for_each(v.begin(), v.end(), pq.add);
But that gives me an error something like "cannot point to member function", hence my solution with a struct, which seems super stupid.



Tonight I've been trying to use pointer-to-member to pass the push function:

int main(int argc, char** argv) {
    priority_queue<int> pq;

    // fill up pq

    vector<int> v;

    while (! pq.emtpy() && pq.top() > 5) {
        v.push_back(pq.top());
        pq.pop();
    }

    void (priority_queue<int>::*add)(int n);
    add = &priority_queue<int>::push;

    for_each(v.begin(), v.end(), (pq.*add));

    return 0;
}



But this gives me the error "Invalid use of non-static member"

Any Suggestions ???

Is This A Good Question/Topic? 0
  • +

Replies To: Using a member function with the STL

#2 KYA  Icon User is offline

  • g++ jameson.cpp -o beverage
  • member icon

Reputation: 3120
  • View blog
  • Posts: 19,163
  • Joined: 14-September 07

Re: Using a member function with the STL

Posted 01 October 2010 - 10:22 PM

Is the for_each that necessary? You could do the equivalent:

for(vector<int>::iterator it = v.begin(); it != v.end(); ++it){
	pq.push(*it);
}



and just be done with it.

In my mind this should work:

//edited
void(priority_queue<int>::*ptr)(const int&) = &priority_queue<int>::push;



but it's not cooperating. I'm sure I'm missing something here.
Was This Post Helpful? 0
  • +
  • -

#3 sarmanu  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 966
  • View blog
  • Posts: 2,362
  • Joined: 04-December 09

Re: Using a member function with the STL

Posted 02 October 2010 - 12:21 AM

Fully agree with KYA, that you overcomplicate things. You can use std::for_each to accomplish what you want though. Easily use std::mem_fun to create a pointer to member function and std::bind1st to return a function object. Here's an example:
#include <iostream>
#include <vector>
#include <queue>
#include <ctime>

class MyQueue
{
private:
	std::priority_queue<int> *pq;
public:
	MyQueue(std::priority_queue<int> *p) : pq(p) {
	}
	void Push(int x)
	{
		pq->push(x);
	}
};

void assignData(std::vector<int> &v)
{
	for (size_t i = 0; i < 10; i++)
		v.push_back(rand() % 35);
}

void printData(std::priority_queue<int> pq)
{
	while (!pq.empty())
	{
		std::cout << pq.top() << "\n";
		pq.pop();
	}
}

int main()
{
	srand(size_t(time(NULL)));
	std::vector<int> v;
	std::priority_queue<int> pq;

	assignData(v);
	MyQueue q(&pq);
	
	std::for_each(v.begin(), v.end(), std::bind1st(std::mem_fun(&MyQueue::Push), &q));

	printData(pq);

	return 0;
}


The above example does what you want, as it copies the elements from a std::vector into a std::priority_queue.
@KYA: that's not how you create a pointer to member functions.

This post has been edited by sarmanu: 02 October 2010 - 12:26 AM

Was This Post Helpful? 0
  • +
  • -

#4 code_m  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 24
  • View blog
  • Posts: 202
  • Joined: 21-April 09

Re: Using a member function with the STL

Posted 02 October 2010 - 11:29 AM

Meh. I was really just hoping there was a nice way to write for_each(v.begin(), v.end(), pq.add); but apparently not. :-(

Also, I didn't think about using a standard for loop with iterators. Not sure really why, I usually don't overlook stuff like that.
Was This Post Helpful? 0
  • +
  • -

#5 KYA  Icon User is offline

  • g++ jameson.cpp -o beverage
  • member icon

Reputation: 3120
  • View blog
  • Posts: 19,163
  • Joined: 14-September 07

Re: Using a member function with the STL

Posted 02 October 2010 - 12:16 PM

I don't think this is possible without a wrapper.

You could make it shorter though:

class QueueWrapper{
private:
	priority_queue<int>* pq;
public:
	QueueWrapper(priority_queue<int>* p):pq(p) {};
	void operator() (int i){
		pq->push(i);
	}
};

int main(){
	priority_queue<int> pq;
	vector<int> v;

	for(int i = 0; i < 5; i++){
		v.push_back(i);
	}

	QueueWrapper test(&pq);

	for_each(v.begin(), v.end(), test);

	while(!pq.empty()){
		cout << pq.top() << endl;
		pq.pop();
	}

	cin.get();
	return 0;
}



You can do a function pointer but the for_each complains since it doesn't have a parameter:

void(priority_queue<int>::*ptr)(const int&) = &priority_queue<int>::push;

for_each(v.begin(), v.end(), ptr);

//and this causes MSVC++ to break
for_each(v.begin(), v.end(), pq.*ptr);



Ideally the second one should work since the foreach only does this:

		// TEMPLATE FUNCTION for_each
template<class _InIt,
	class _Fn1> inline
	_Fn1 _For_each(_InIt _First, _InIt _Last, _Fn1 _Func)
	{	// perform function for each element
	for (; _First != _Last; ++_First)
		_Func(*_First);
	return (_Func);
	}




Which if we wrote it by hand would look like:

void(priority_queue<int>::*ptr)(const int&) = &priority_queue<int>::push;
	for(vector<int>::iterator it = v.begin(); it != v.end(); ++it){
		(pq.*ptr)(*it);
	}


Was This Post Helpful? 0
  • +
  • -

#6 Bench  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 857
  • View blog
  • Posts: 2,343
  • Joined: 20-August 07

Re: Using a member function with the STL

Posted 03 October 2010 - 02:47 AM

View Postcode_m, on 02 October 2010 - 06:29 PM, said:

Meh. I was really just hoping there was a nice way to write for_each(v.begin(), v.end(), pq.add); but apparently not. :-(
Firstly, you're using the wrong algorithm - you're trying to copy the contents of 'v' into your priority queue - this implies the std::copy algorithm.

With STL containers which fit the container concept, there exists a standard tool called an insert iterator; however, the std::stack, std::queue and std::priority queue are classed as wrappers rather than containers (i.e. they are wrapper interfaces for STL containers), and noone thought to provide the same functionality for those.

Personally, I believe it would be useful for the standard container wrappers to support insert-iterators; in fact, there's no reason to my mind why there should be no support for this functionality (You just have to write it yourself).

A standard tool called back_inserter exists for use with vector/deque/list/etc; Its just as viable to write a tool to "push" something onto a queue, stack or priority queue using another kind of inserter. (push inserter? wrapper inserter?)
#include <iostream>
#include <iterator>
#include <algorithm>
#include <queue>
#include <vector>

template <class Wrapper>
class wrapper_insert_iterator :
    public std::iterator<std::output_iterator_tag,void,void,void,void>
{
    Wrapper& wrapper;
public:
    typedef typename Wrapper::container_type container_type;
    wrapper_insert_iterator<Wrapper>(Wrapper& w)
        : wrapper(w) {}
    wrapper_insert_iterator<Wrapper>& operator= (typename Wrapper::container_type::const_reference value)
    {
        wrapper.push(value);
        return *this;
    }
    wrapper_insert_iterator<Wrapper>& operator*() { return *this; } 
    wrapper_insert_iterator<Wrapper>& operator++() { return *this; }
    wrapper_insert_iterator<Wrapper>& operator++(int) { return *this; }
}; 

template<typename Wrapper>
wrapper_insert_iterator<Wrapper> push_inserter(Wrapper& w)
{
    return wrapper_insert_iterator<Wrapper>(w);
}

int main()
{
    int arr[] = { 1,2,3,4,5 };
    std::vector<int> vec(arr, arr+( sizeof arr / sizeof arr[0] ) );

    std::priority_queue<int> pq;
    std::copy(vec.begin(), vec.end(), push_inserter(pq));

    while(!pq.empty())
    {
        std::cout << pq.top() << std::endl;
        pq.pop();
    }
}



There's a nice article which discusses insert iterators here:
http://www.angelikal...tIterators.html

This post has been edited by Bench: 03 October 2010 - 03:00 AM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1