Reputation: 101496
Follow-up to post: Using * Width & Precision Specifiers With boost::format
I'm trying to use boost::function
to create a function that uses lambdas to format a string with boost::format
. Ultimately what I'm trying to achieve is using width & precision specifiers for strings with format. boost::format
does not support the use of the *
width & precision specifiers, as indicated in the docs:
Width or precision set to asterisk (*) are used by printf to read this field from an argument. e.g. printf("%1$d:%2$.*3$d:%4$.*3$d\n", hour, min, precision, sec); This class does not support this mechanism for now. so such precision or width fields are quietly ignored by the parsing.
so I'm trying to find other ways to accomplish the same goal.
Here is what I have so far, which isn't working:
#include <string>
#include <boost\function.hpp>
#include <boost\lambda\lambda.hpp>
#include <iostream>
#include <boost\format.hpp>
#include <iomanip>
#include <boost\bind.hpp>
int main()
{
using namespace boost::lambda;
using namespace std;
boost::function<std::string(int, std::string)> f =
(boost::format("%s") % boost::io::group(setw(_1*2), setprecision(_2*2), _3)).str();
std::string s = (boost::format("%s") % f(15, "Hello")).str();
return 0;
}
This generates many compiler errors:
1>------ Build started: Project: hacks, Configuration: Debug x64 ------
1>Compiling...
1>main.cpp
1>.\main.cpp(15) : error C2872: '_1' : ambiguous symbol
1> could be 'D:\Program Files (x86)\boost\boost_1_42\boost/lambda/core.hpp(69) : boost::lambda::placeholder1_type &boost::lambda::`anonymous-namespace'::_1'
1> or 'D:\Program Files (x86)\boost\boost_1_42\boost/bind/placeholders.hpp(43) : boost::arg<I> `anonymous-namespace'::_1'
1> with
1> [
1> I=1
1> ]
1>.\main.cpp(15) : error C2664: 'std::setw' : cannot convert parameter 1 from 'boost::lambda::placeholder1_type' to 'std::streamsize'
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>.\main.cpp(15) : error C2872: '_2' : ambiguous symbol
1> could be 'D:\Program Files (x86)\boost\boost_1_42\boost/lambda/core.hpp(70) : boost::lambda::placeholder2_type &boost::lambda::`anonymous-namespace'::_2'
1> or 'D:\Program Files (x86)\boost\boost_1_42\boost/bind/placeholders.hpp(44) : boost::arg<I> `anonymous-namespace'::_2'
1> with
1> [
1> I=2
1> ]
1>.\main.cpp(15) : error C2664: 'std::setprecision' : cannot convert parameter 1 from 'boost::lambda::placeholder2_type' to 'std::streamsize'
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>.\main.cpp(15) : error C2872: '_3' : ambiguous symbol
1> could be 'D:\Program Files (x86)\boost\boost_1_42\boost/lambda/core.hpp(71) : boost::lambda::placeholder3_type &boost::lambda::`anonymous-namespace'::_3'
1> or 'D:\Program Files (x86)\boost\boost_1_42\boost/bind/placeholders.hpp(45) : boost::arg<I> `anonymous-namespace'::_3'
1> with
1> [
1> I=3
1> ]
1>.\main.cpp(15) : error C2660: 'boost::io::group' : function does not take 3 arguments
1>.\main.cpp(15) : error C2228: left of '.str' must have class/struct/union
1>Build log was saved at "file://c:\Users\john\Documents\Visual Studio 2005\Projects\hacks\x64\Debug\BuildLog.htm"
1>hacks - 7 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
My fundamental understanding of boost's lambdas and functions is probably lacking. How can I get this to work?
Upvotes: 0
Views: 3064
Reputation: 100748
I think that, for this case, you would want to use boost.bind instead of boost.lambda. Part of the problem is that boost::io::group is a function template that takes and returns a variable number of objects, making it difficult to create the appropriate signature for the function<> declaration. I would create a string formatting function with a simple signature and then use boost.bind to create a specific formatting functor from that. i.e.
#include <string>
#include <iomanip>
#include <boost/function.hpp>
#include <boost/format.hpp>
#include <boost/bind.hpp>
using namespace boost;
using namespace std;
string fmt_str(const string& s, int w, int p)
{
return (format("%s") % io::group(setw(w), setprecision(p), s)).str();
}
int main()
{
function<string (int, string)> f = bind(fmt_str, _2, _1, _1);
string s = f(15, "Hello");
return 0;
}
Upvotes: 2
Reputation: 28117
You should check the documentation of Boost.Lambda again and see what it is capable of and what not. For example, since the dot operator is not overloadable you can't invoke a member function like str()
on a lambda expression like that. You need to use bind
for this:
bind(&format::str, … )
This actually extends to all non-operator function calls as far as I can tell. As for creating a format object you need to defer the creation of it via something like this:
constructor<boost::format>(constant("%s")) // untested
You see that with all the extra noise (bind, constructor, constant) you get a rather complex, long, and hard to decipher lambda expression. The best thing is probably to avoid it altogether and just use a simple function object
struct myfunctor {
string operator()(int a, string b) const {
return …
}
};
…
void foo() {
…
boost::function<string(int, string)> f = myfunctor();
…
}
Upvotes: 1