g++ (at least versions 3.3.5, 3.4.4 and 4.1.1) accepts the following code, which I think is ill-formed: template<typename T> struct F {}; template<typename C, typename R> int f(R (C::*f)() const, const F<R> &n = F<R>()) { return 0; } // f0 template<typename C, typename R> int f(const R &(C::*f)() const, const F<R> &n = F<R>()) { return 1; } // f1 struct X { const X &foo() const { return *this; } }; int main() { return f(&X::foo); } Here, g++ is presumably deciding that f1 is more specialized than f0, despite f0's arguments not being deducible from f1 (indeed, there is no pair of argument types (T1, T2) which both f0 and f1 accept). EDG's frontend rejects the above code.
FWIW, Microsoft's recent compilers agree that this is ill-formed also.
It's still warning free on 4.3.1 (except with all turned on, when ti complains about unused parameters but nothing else). As far as I can tell the second template matches the subset of the matches for the first template where R would be an const ? &, with the second parameter matching a different but still default constructed type. It's not ambiguous because of the const at least. I don't see why this would not work? Do you have an std reference for why this would be ill-formed?
I'm not 100% certain that g++ is at fault. Given that icc, Comeau and MS all reject it, I'm inclined to think that g++ is probably the one which gets this wrong, so I've raised this here first. This hinges on whether f0 and f1 are ordered by the standard partial ordering on function templates. It appears superficially that they are not, since from the arguments to f1 you cannot deduce the template parameters of f0, nor vice versa. However, it appears to depend on interpretation of [temp.deduct.type]/5, which says that "The non-deduced contexts are: [...] A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done". I'm not sure whether that applies here, but if it does, perhaps that makes f1 more specialized than f0, and this is a bug in all the other compilers.
Current ICC and Clang accept this, like GCC. Jason, can you double check that we are already doing the right thing?
N3281 changed the rules such that g++ is now correct.
Ah, great, thanks!