why does the first assignment not call the template operator = in Foo, but the second does? What's going on here?
In addition to the fact explained by William, the answer to the implicitly generated function of the copy assignment operator, in this case there is also permission to overload. Below are the candidates for the first assignment operator after replacing the argument template, as seen by the compiler:
Foo& operator=(const Foo&);
All things being equal, nontemplate functions are preferable to functional templates. In accordance with C ++ 11 (project N3337), 13.3.3 / 1 (emphasis mine)
Given these definitions, a viable function F1 is defined as a better function than another viable function F2, if for all arguments i, ICSi (F1) is no worse than the transformation scheme than ICSi (F2), and then
- for some argument j, ICSj (F1) is a better conversion sequence than ICSj (F2), or, if not this,
- the context is initialization by user conversion (see 8.5, 13.3.1.5 and 13.3.1.6) and the standard conversion sequence from the return type F1 to the destination type (i.e., the initialization type of the object) is a better conversion sequence than the standard conversion sequence from return type F2 to destination type. [...] or, if not this,
- F1 is a function without a template, and F2 is a specialized function of a template , or, if not this,
- F1 and F2 are specialized function templates, and the function template for F1 is more specialized than the template for F2 in accordance with the partial ordering rules described in 14.5.6.2.
This explains why non-template overload is selected. You can check the same with a little exercise:
void print(int, int) { std::cout << "int"; } template <typename T> void print(T, T) { std::cout << "T"; } print(1, 2);
As for the second assignment, he sees
Foo& operator=(const Foo&);
Here, the generated function template is closer than the implicitly generated function, and therefore it was selected.