Это:
foo& operator=(const auto& f);
не будет стандартным кодом C ++ до C ++ 20. Но gcc разрешил это в течение достаточно долгого времени, и это означает:
template <typename _T>
foo& operator=(const _T& f);
Другими словами, это шаблон оператора присваивания. Это , а не оператор копирования. Это должно быть не шаблон. Поскольку вы не предоставили оператор присваивания копии, компилятор с радостью сгенерирует его для вас. В первом примере кода вы указали свой собственный оператор назначения копирования.
Когда вы пишете:
f1 = f2;
В вашем первом примере у этого выражения есть один кандидат: оператор присвоения копии, который вы написали. Во втором примере есть два кандидата: ваш шаблон оператора присваивания и оператор присваивания копии, синтезированный компилятором. Компилятор лучше подходит (не шаблонный шаблон), поэтому он вызывается, а не ваш.