"for(...;...; ..., (void)++_First)" - в чем замысел (void)?
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 08.03.17 20:20
Оценка:
Разглядывая содержимое <xmemory> (VS2017) увидел странные конструкции:

for (; 0 < _Count; --_Count, (void)++_First)
//....
for (; _First != _Last; ++_Dest, (void)++_First)

Зачем здесь (void)?

А в <xmemory> VS2015 увидел вот такое:
for (; 0 < _Count; --_Count, (void)++_Dest, ++_First)

Вообще не понятно ...

----
Может это типа новое слово в подсказках оптимизатору компилятора?

То есть, мы как бы говорим, что нам не интересен результат оператора ++ и соответствующий (процессорный) код ( return *this; ) можно не генерировать?
Это единственное объяснение, которое пришло в мне в голову
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re: "for(...;...; ..., (void)++_First)" - в чем замысел (voi
От: watchmaker  
Дата: 08.03.17 20:40
Оценка: 149 (22)
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>
КД>for (; _First != _Last; ++_Dest, (void)++_First)
КД>

КД>Зачем здесь (void)?

Защита от переопределения operator,.
Если этот оператор задан, то запись ++_Dest, ++_First может означать (++Dest).operator,(++_First), то есть делать совсем не то, что было задумано.
А так как оператор запятая не может принимать одним из своих аргументов void, то в конструкции ++_Dest, (void)++_First он никогда не вызовется.
Отредактировано 08.03.2017 20:52 watchmaker . Предыдущая версия .
Re[2]: "for(...;...; ..., (void)++_First)" - в чем замысел (voi
От: N. I.  
Дата: 09.03.17 09:32
Оценка: 98 (6)
watchmaker:

W>А так как оператор запятая не может принимать одним из своих аргументов void, то в конструкции ++_Dest, (void)++_First он никогда не вызовется.


Если подходить к вопросу совсем уж педантично, то надо оба операнда приводить к void. Когда хотя бы один из операндов запятой имеет пользовательский тип, перегруженные запятые рассматриваются, даже если другой операнд имеет тип void. Конечно, ни один из кандидатов не пройдёт как минимум из-за несоответствия критерию "viable function", однако до отсева по этому критерию дело может просто не дойти из-за появления ошибки, ставящей крест на успешной компиляции.

template <class T>
    struct A
{
    typedef typename T::value_type type;
};

struct X
{
    template <class T>
        typename A<T>::type operator ,(T const &);
};

struct Y
{
    template <class T>
        friend typename A<T>::type operator ,(T const &, Y const &);
};

int main()
{
    void(), X(); // OK
    X(), void(); // error: instantiation of A<void> produces invalid construct void::value_type
    void(), Y(); // error: instantiation of A<void> produces invalid construct void::value_type
}

Здесь выражение X(), void() приведёт к инстанцированию объявления функции typename A<void>::type X::operator ,(void const &), что, в свою очередь, приведёт к инстанцированию определения класса A<void>, где мы получаем void::value_type. Конструкция void::value_type не относится к immediate context объявления typename A<void>::type X::operator ,(void const &), поэтому SFINAE тут не сработает и это будет фатальной ошибкой компиляции.

Аналогично с void(), Y() — этот случай я привёл просто ради симметрии.
Re[2]: "for(...;...; ..., (void)++_First)" - в чем замысел (voi
От: Serg27  
Дата: 10.03.17 03:56
Оценка: 2 (1)
Здравствуйте, watchmaker, Вы писали:

W>Защита от переопределения operator,.

W>Если этот оператор задан, то запись ++_Dest, ++_First может означать (++Dest).operator,(++_First), то есть делать совсем не то, что было задумано.
W>А так как оператор запятая не может принимать одним из своих аргументов void, то в конструкции ++_Dest, (void)++_First он никогда не вызовется.
Спасибо, задумался. Сходил на cppreference. Там мне больше понравился другой вид записи этого же выражения:
a,void(),b
Мне кажется эта запись более понятна, чем с приведением к типу void и более ясно говорит о целях этой записи.
Цитата:

The comma operator, operator,. Unlike the built-in version, the overloads do not sequence their left operand before the right one. (until C++17) Because this operator may be overloaded, generic libraries use expressions such as a,void(),b instead of a,b to sequence execution of expressions of user-defined types.

Re[2]: "for(...;...; ..., (void)++_First)" - в чем замысел (voi
От: Alexander G Украина  
Дата: 10.03.17 09:03
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Защита от переопределения operator,.


Мне вот интересно, кто в здравом уме будет перегружать запятую для итератора.

С учётом того, что итератор, скорее всего, будет использовать не только в супер-обобщенной реализации STL, но и в обычном прикладном коде, в котором запятую используют не задумываясь.
Русский военный корабль идёт ко дну!
Re[3]: "for(...;...; ..., (void)++_First)" - в чем замысел (voi
От: N. I.  
Дата: 10.03.17 11:19
Оценка:
Alexander G:

AG>Мне вот интересно, кто в здравом уме будет перегружать запятую для итератора.


Возможно, кто-нибудь захочет запись диапазонов в виде (i, j) с проверкой их корректности в дебаг-сборке. Тогда выражение вроде ++i, ++j может выплюнуть assertion failure из-за того, что данная пара итераторов не образует допустимый диапазон. Автору шаблона, вероятно, проще сделать void(++i), void(++j), чем потом разбираться с баг-репортами на этот счёт (формально обоснованными, кстати, если требование не перегружать запятую таким образом нигде в предусловиях не оговорено).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.