3

I'm porting a project from MSVC to Borland C++ and I'm running into difficulties with template functions. For example, the following

void fn(const char *buffer)
{
  vector<string> output;
  boost::split(output, string(buffer), is_any_of(","));
  // ...

causes a compiler error:

[BCC32 Error] example.cpp(208): E2285 Could not find a match for 'split<SequenceSequenceT,RangeT,PredicateT>(vector<string,allocator<string> >,string,is_any_ofF<char>)'

whereas the modified example

void fn(const char *buffer)
{
  vector<string> output;
  string sBuffer(buffer);
  boost::split(output, sBuffer, is_any_of(","));
  // ...

compiles fine.

The generalization of this problem, as indicated in the post title, is that in certain cases BCC does not seem to match the template function if arguments are passed in as temporary objects that are constructed inside the function's argument list.

Before changing all the affected code, I'd like to understand why BCC thinks the first example is wrong. Is this a deficiency of the compiler, or does my code not comply to C++ standards?

I'm using RAD Studio / C++ Builder XE2.

Syscall
  • 19,327
  • 10
  • 37
  • 52
Hendrik
  • 569
  • 3
  • 12
  • 4
    "I'm porting a project from MSVC to Borland C++" oh I pity the hells in which you must suffer. – Tony The Lion Sep 25 '12 at 12:07
  • "I'm porting a project from MSVC to Borland C++" I stopped reading at this point. – Bartek Banachewicz Sep 25 '12 at 12:24
  • 2
    Does `boost::split` take the argument by reference, `const` reference or value? If the first, it is right to error because you can't bind a non-`const` reference to a temporary. – Seth Carnegie Sep 25 '12 at 12:26
  • 2
    This is just a guess but if boost::split takes a reference as the second argument I think you need to create the object before and pass it in. – dutt Sep 25 '12 at 12:26
  • 2
    Well, thanks for the condolescences. If you want to know the details, I'm reverting a migration from BCC to MSVC, which has proven to be infeasible... so it is in fact "hell and back again". – Hendrik Sep 25 '12 at 12:27
  • @SethCarnegie and dutt: good point, I'll have a closer look. – Hendrik Sep 25 '12 at 12:29
  • @dutt and SethCarnegie: you are both right. `split` takes a reference for its first and second argument, but not its third argument. This explains everything but the fact that MSVC does not even print out a warning. – Hendrik Sep 25 '12 at 12:33

2 Answers2

3

From the Boost manual

template<typename SequenceSequenceT, typename RangeT, typename PredicateT> 
  SequenceSequenceT & 
  split(SequenceSequenceT & Result, RangeT & Input, PredicateT Pred, 
        token_compress_mode_type eCompress = token_compress_off);

It seems like the function does indeed take its parameters by reference, so your "workaround" is actually the correct way of using it.

MSVC is known to allow binding to a non-const reference as an "extension".

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
3

It's not because the function is a template; it's because for some reason it takes its Input argument as a non-const lvalue reference, as documented here:

template<typename SequenceSequenceT, typename RangeT, typename PredicateT> 
  SequenceSequenceT & 
  split(SequenceSequenceT & Result, RangeT & Input, PredicateT Pred, 
        token_compress_mode_type eCompress = token_compress_off);

In standard C++, you can't bind a temporary rvalue, such as string(buffer), to such a reference. In Microsoft's imaginative reinterpretation of the language, you can.

The solution is to do exactly what you've done: introduce a named, non-temporary variable which can be passed by reference.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644