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() — этот случай я привёл просто ради симметрии.