Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Portability issue with template function Instantiation

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.

like image 687
Hendrik Avatar asked Mar 12 '26 19:03

Hendrik


2 Answers

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.

like image 66
Mike Seymour Avatar answered Mar 15 '26 08:03

Mike Seymour


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".

like image 25
Bo Persson Avatar answered Mar 15 '26 09:03

Bo Persson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!