views:

184

answers:

2

Hi all,

I am having problems compiling the following snippet

int temp; 
vector<int> origins;

vector<string> originTokens = OTUtils::tokenize(buffer, ","); // buffer is a char[] array

// original loop 
BOOST_FOREACH(string s, originTokens)
{
    from_string(temp, s);
    origins.push_back(temp);
}    

// I'd like to use this to replace the above loop
std::transform(originTokens.begin(), originTokens.end(), origins.begin(), boost::bind<int>(&FromString<int>, boost::ref(temp), _1));

where the function in question is

// the third parameter should be one of std::hex, std::dec or std::oct
template <class T>
bool FromString(T& t, const std::string& s, std::ios_base& (*f)(std::ios_base&) = std::dec)
{
    std::istringstream iss(s);
    return !(iss >> f >> t).fail();
}

the error I get is

1>Compiling with Intel(R) C++ 11.0.074 [IA-32]... (Intel C++ Environment)
1>C:\projects\svn\bdk\Source\deps\boost_1_42_0\boost/bind/bind.hpp(303): internal error: assertion failed: copy_default_arg_expr: rout NULL, no error (shared/edgcpfe/il.c, line 13919)
1>
1>          return unwrapper<F>::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_]);
1>                                                                                ^
1>
1>icl: error #10298: problem during post processing of parallel object compilation

Google is being unusually unhelpful so I hope that some one here can provide some insights.

UPDATE: Question is answered by @gf's solution, but interestingly the original function wasn't quite correct as it stored the result of the conversion operation (failed/not failed) rather than the converted value itself. I changed the signature return the converted value directly and the compiler was able to infer the type of the binding correctly.

// new signature
T FromString(const std::string& s, std::ios_base& (*f)(std::ios_base&) = std::dec);

// revised calling syntax - note that bind<int> is not required. 
transform(originTokens.begin(), originTokens.end(), origins.begin(),  bind(&FromString<int>, _1, std::dec));
A: 

Function templates aren't supported by boost::bind. You should turn the function into a function object:

template< typename T> 
struct from_string {
  bool operator()(T& t, std::string const& s, std::ios_base& (*f)(std::ios_base&) = std::dec) {
    std::istringstream iss(s);
    return !(iss >> f >> t).fail();
  }
};

usage:

boost::bind< bool >(from_string< int >(), boost::ref(temp), _1)
VuuRWerK
The OP isn't passing a template function but rather a specific instantiation of it - `FromString<int>()`.
Georg Fritzsche
VuuRWerK
@VuuR: I assure you, its portable standard-compliant syntax and a specific instantiation of a template function is no different than a common one in a function pointer context.
Georg Fritzsche
+2  A: 

FromString() takes 3 arguments and default arguments are not part of a functions type. So the bind expression should probably be something like:

boost::bind<int>(&FromString<int>, boost::ref(temp), _1, std::dec);
Georg Fritzsche
That is exactly the problem! Thanks. That error message is pretty darn uninfomative isn't it :)
Jamie Cook
@Jamie: since this is the solution, and you have accepted it, I take it that you agree in that it is a good answer and should thus be upvoted?
David Rodríguez - dribeas
@Jamie: I know, Boost.Bind errors are probably among the most non-descriptive ones and VCs cl.exe even likes to crash over these.
Georg Fritzsche
@DavidRodriguez: it is useful and that is why I have marked it as the accepted answer. I fail to see how also marking it with an upvote is required.
Jamie Cook
@gf: I'm just starting to use the library a bit more, it's funny tho that there isn't an easier way to do simple stuff like this (transformations I mean). Maybe ruby has just spoiled me too much :)
Jamie Cook
@Jamie: C++0x lambdas will help but i doubt i'll be using them soon at work. As for the voting: the intent as per the FAQ is roughly *"vote up the helpful answers and accept the most helpful one"* - but thats of course entirely up to you.
Georg Fritzsche
the intel 11.0 compilers support lambdas but as you say being supported and catching on are two different things entirely. The one place they could be really useful is in multi-threading esp when combined with the TBB library [http://software.intel.com/en-us/blogs/2009/08/03/parallel_for-is-easier-with-lambdas-intel-threading-building-blocks/]. regarding the upvotes, my interpretation was upvotes for all helpful answers *except* the accepted answer, which gets the big tick - as you say, subjective, and I didn't mean to convey that your answer wasn't helpful.
Jamie Cook