Как разрешить преобразование временного в l-значение для C++98 API

У меня есть C++98 API, который принимает значение по неконстантной ссылке и изменяет это значение.
В частности, я использую OpenCV и функция cv::rectangle() который занимает cv::Mat & изображение для рисования.

Этот же API также использует шаблоны выражений для оптимизации арифметики изображений. Я могу нарисовать прямоугольник в области интереса (ROI), создав (неконстантный) временный объект-обертку, который представляет субизображение.

С VS2010 я могу написать:

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 << !!!

Это работает без проблем. В строке (2) создается временный объект-обертка подизображения и передается cv::rectangle по ссылке.

Однако в XCode для iOS с Clang с поддержкой C++11 строка (2) выдает следующую ошибку:

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

Для полноты вот соответствующий прототип:

//! 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);

Я думаю, что это происходит потому, что a(rec) создает временный объект, который передается по ссылке cv::rectangle и компилятор не позволяет преобразовать это временное значение в l-значение. Возможно, этот временный объект автоматически определяется как const?
Я действительно передаю временное, но временное является оберткой для фактического неконстантного l-значения и должно быть свободно изменено.

Есть ли способ сказать Clang, чтобы ослабить эти ограничения?
Можно ли как-то сказать компилятору, что эти заголовки происходят из библиотеки C++ 98 и, следовательно, должны обрабатывать временные значения, как в C++98? Что-то сродни делать extern "C"?
Есть ли способ разрешить преобразование временного в l-значение.

Конечно, я могу написать auto b=a(rec) и передать b вместо этого, но это заполняет код кучей именованных временных и превосходит назначение классов-оболочек.

1 ответ

Решение

Отвечая самому себе... после некоторого дополнительного исследования кажется, что это поведение продиктовано стандартом, и VS2010 здесь не соответствует.
Такое поведение было разработано для предотвращения случайных ошибок, хотя мой вариант использования фактически является примером действительного варианта использования, который запрещен стандартом.

Правило: неконстантные временные файлы НЕ связываются с неконстантными ссылками.
Отличие от временных const заключается в том, что вы можете вызывать неконстантные методы для временных.
Если такой метод возвращает, например, *this, тогда этот результат будет l-значением и, таким образом, будет привязан к неконстантной ссылке.

Для получения дополнительной информации смотрите здесь и здесь.

Как сказано выше в @Xeo, в C++11 также можно написать преобразователь из значения r в значение l: template<class T> T& as_lvalue(T&& v){ return v; } // add 'hazard' icon,
Тем не менее, это следует использовать с особой осторожностью (или не использовать вообще).

Другие вопросы по тегам