Domanda

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.

È stato utile?

Soluzione

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top