Как разрешить преобразование временного в 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
,
Тем не менее, это следует использовать с особой осторожностью (или не использовать вообще).