Open apolukhin opened 3 years ago
yndx-antoshkka, 15 октября 2018, 17:44 У этого расширения очень большие проблемы:
void increment(long& foo) { foo += 1; }
int main() {
int x = 123;
increment(x);
assert(x == 124); // Oops!
}
Сами инженеры из MSVC рекомендуют не пользоваться этой особенностью.
Даниил Милютин, 15 октября 2018, 18:19 yndx-antoshkka, Ваш контр-пример не скомпилируется MSVC
void increment(long& foo) { foo += 1; }
struct X
{
X(long* x): i(x) {}
long* i = nullptr;
};
void increment(X& foo) { *foo.i += 1; }
int main() {
int x = 123;
long ll = 123;
//increment(x); // MSVC won't allow that
// implicit type conversion in this case is forbidden!
increment(ll); // fine
increment(X(&ll)); // fine
//assert(x == 124); // Oops!
//assert(ll == 125); // Fine
return ll;
}
Моё предложение касается случаев, когда при implicit конвертации не создаётся новых объектов на стеке. В вашем примере (если б это работало по логике полного расслабления требований) создастся временный объект типа long. И я такое также ни в коей мере не поощряю. То есть предложение звучит "как расслабить требования, но с ограничениями".
Ваше видение предложения изменилось после моих уточнений? :)
Andrey Davydov, 16 октября 2018, 12:58 Даниил Милютин, MSVC ведят себя еще более странно -- важно не только то, создается ли временный объект явно или нет, но и является ли он примитивным типом: к примеру, increment((long)x) тоже не скомпилируется.
Даниил Милютин, 17 октября 2018, 3:08 Andrey Davydov, Такое поведение компилятора MSVC меня лично тоже устривает. Собственно свои идеи и уочнения я изложил.
Жду от коллег по цеху выраженных мыслей по этому поводу. Если есть ещё логические доводы против, то мне интересно их воспринять.
webreh, 20 ноября 2018, 20:46 Преобразование prvalue of T в T& является предупреждением 4238: nonstandard extension used: class rvalue used as lvalue. Оно было нужно в С++03 и бесполезно с появлением форм auto&&.
Перенос предложения: голоса +0, -4 Автор идеи: Даниил Милютин
Пример.
См. также: Пример (by Jason Turner): https://www.youtube.com/watch?v=SnTV5BU9x6k
Пример горького опыта близкий к моему: https://forum.kde.org/viewtopic.php?f=74&t=88577
Предлагается позволить указанному расширению MSVC войти в новый стандарт.
З.Ы. Какие обходы для текущей стуации? 1) Перегружать функцию принающую rv-reference. Не хочется по причине разрастания boilerplate. К тому же если, аргументов больше одного (N), то придётся писать 2^N вариантов. Совсем не хочется.
2) Также можно было бы передавать ReferenceType по значению. Но это увеличит число копирований. А ReferenceType всё таки может весить побольше.
3) Самый неправильный (и быстрый по написанию, и возможно по работе) workaround - это нагло врать компилятору. Прописывать аргумент как постоянную ссылку, а внутри приводить с const_cast к мутабельному состоянию. В примере выше можно и без оного - в лоб, ибо const int* позволит мутировать данные, на которые указывает. Однако если ReferenceType устроен сложнее (например, содержит данные защищённо и к данным имеет доступ только через non-const методы), то придётся делать const_cast.