boost::bind

Mar 11, 2011 at 7:06am
So, I have a function that basically looks like this:

1
2
3
4
5
6
7
8
template <class T, class save_func_type>
inline void save_container(std::ostream& file, const std::string& name, const T& data, save_func_type save_func) {
	file<<"#begin"<<name<<"n";
	for(T::const_iterator iter = data.begin(); iter != data.end(); ++iter) {
		save_func(file, name+"_obj", *iter);
	}
	file<<"#end"<<name<<"n";
}


And am calling it like this:

1
2
void (*fp)(std::ostream&, const std::string&, const std::string&) = &util::file::save_line<std::string>;
util::file::save_container(file, "keywords", obj.keywords, boost::bind(fp, _1, _2, _3));


I am getting this error:
Error 5 error C2664: 'void (std::ostream &,const std::string &,const std::string &)' :
cannot convert parameter 1 from 'const std::ostream' to 'std::ostream &' c:program files (x86)boostboost_1_44boostbindbind.hpp 392


Is this a problem with my code? This is first time I've really used bind so it could be I screwed something up. Or is it just a problem with the references/constness of the function parameters?
Last edited on Mar 11, 2011 at 7:07am
Mar 11, 2011 at 2:01pm
It is both. By default, boost::bind makes copies of arguments. The usual way around this is to use boost::ref(),
but in your case, doing boost::ref( _1 ) doesn't make sense, since you're making a reference to the placeholder,
not the actual parameter passed on line 5.

I _think_ your T is a template parameter just because of the container type -- in all cases you are expecting the
container to hold std::strings. If that is the case, you can try this: (I have not tried it or even compiled it)

1
2
3
4
5
6
7
8
9
template< typename Containe >
inline void save_container( std::ostream& file, const std::string& name, const Container& data,
    const boost::function<void( std::ostream&, const std::string&, const std::string& ) >& save_func )
{
    file << "#begin" << name << "n";
    for( Container::const_iterator iter = data.begin(); iter != data.end(); ++iter )
        save_func( file, name + "_obj", *iter );
    file << "#end" << name << "n";
}


Not sure if this will work. The point is that the compiler needs to know when compiling the save_func() call that it
needs to pass the first parameter by non-const reference instead of by value.
Mar 11, 2011 at 6:39pm
Ok, I think I understand.

However, the problem is that the container might not be just of std::strings, it could be of any type.
In the case that I was showing, I was using an std::string, but somewhere else I might need to save a container of ints or something. That was originally why I was trying to pass a function pointer as the save function.

e.g.:
1
2
void (*fp)(std::ostream&, const std::string&, const some_type&) = &util::file::save_line<some_type>;
util::file::save_container(file, "some_types_container", obj.some_types, boost::bind(fp, _1, _2, _3));


The only reason why I need something like boost::bind was because (as shown) the save_func is supposed to take 3 arguments. However, if I am saving a container of another container, I would need to also pass the function pointer to save those contained elements as well. However, since it was constant I thought that maybe I could use bind to simply bind the last argument (the save_func pointer) so that it could still be called with only 3.

Thinking about that however...it seems like the syntax would get really ugly really fast. Maybe I'll just have to do it manually...I'll have to think about it some more.
Mar 12, 2011 at 12:45am
I was looking at the documentation and it looks like it is an issue with the "forwarding problem."
http://www.boost.org/doc/libs/1_46_0/libs/bind/bind.html#Limitations

Guess I'll be making my own save function wrapper for this then.
Topic archived. No new replies allowed.