Pregunta

I have C++98 API that takes a value by non-const reference and changes this value.
Specifically, I'm using OpenCV and the function is cv::rectangle() which takes a cv::Mat & image to be drawn upon.

This same API also uses expression templates to optimize image arithmetic. I can draw a rectangle on a Region-of-Interest (ROI) by creating a (non-const) temporary wrapper object that represents a sub-image.

With VS2010, I can write:

cv::Mat a(10,10,CV_8UC1); // create 10x10 image
Rect rec(0,0,2,2);        // create 2x2 rectangle
cv::rectangle(a, rec, cv::Scalar::all(0));      // (1) draw 2x2 on full image
cv::rectangle(a(rec), rec, cv::Scalar::all(0)); // (2) draw 2x2 on 2x2 sub-image << !!!

This works without a problem. On line (2) a temporary sub-image wrapper object is created and passed to cv::rectangle by reference.

However, on XCode for iOS with Clang with C++11 support, line (2) give the following error:

.../test.cpp:605:5: No matching function for call to 'rectangle'
.../core.hpp:2594:17: Candidate function not viable: expects an l-value for 1st argument 

For completeness, here's the relevant prototype:

//! draws the rectangle outline or a solid rectangle covering rec in the image
CV_EXPORTS void rectangle(CV_IN_OUT Mat& img, Rect rec,
                          const Scalar& color, int thickness=1,
                          int lineType=8, int shift=0);

I think this happens because a(rec) creates a temporary that is being passed by ref to cv::rectangle and the compiler does not allow this temporary to be converted to an l-value. Perhaps this temporary is automatically defined as const?
I am indeed passing a temporary, but the temporary is a wrapper for an actual non-const l-value and should be allowed to change freely.

Is there a way to tell Clang to relax these constraints?
Is it somehow possible to tell the compiler that these headers are coming from a C++98 library and thus should handle temporaries like in C++98? Something akin to doing extern "C"?
Is there a way to allow conversion of the temporary to an l-value.

Of course, I can write auto b=a(rec) and pass b instead, but that fills up the code with a bunch of named temporaries and beats the purpose of the wrapper classes.

¿Fue útil?

Solución

Answering myself... after some more research it seems that this behavior is dictated by the standard, and VS2010 is non-conformant here.
This behavior was designed to prevent accidental errors, though my use-case is actually an example for a valid use-case that is forbidden by the standard.

The rule: non-const temporaries do NOT bind to non-const references.
The difference from const temporaries, is that you can call non-const methods on the temporary.
If such a method returns, e.g. *this, then that result will be an l-value and will, thus, bind to the non-const reference.

For more info see here and here.

As @Xeo comments above, in C++11 it's also possible to write a converter from an r-value to an l-value: template<class T> T& as_lvalue(T&& v){ return v; } // add 'hazard' icon.
However, this should be used with extra care (or not at all).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top