Templated operator overload resolution, member vs non-member function - c++

When trying out clang-3.4 (compiled from git), it failed to compile one of my projects complaining about ambiguity while resolving overloaded operators.
I turned out that there were two templated operators, one of which was declared as a member function, other as a non-member one, which both seems equally good match.
Following SSCCE demonstrates the situation:
#include <iostream>
struct ostr {
std::ostream& s;
template<class T>
ostr& operator<<(const T& x) { s << x; return *this; }
};
struct xy {
double x, y;
};
template<class Stream>
Stream& operator<<(Stream& s, const xy& x) {
s << "[" << x.x << ", " << x.y << "]";
return s;
}
int main() {
ostr os{std::cout};
xy x{4, 5};
os << "Value is: " << x <<"\n";
}
The project compiled fine before and I checked again this SSCCE with several compilers (gcc 4.5, 4.6, 4.7, 4.8 and clang 3.3) and all of them compiled it without any warning (with -Wall -Wextra -pedantic). All compilers were set to C++11/C++0x standard.
After adding ctor to ostr, it compiled fine even on MSVC 2012 and 2010)
Making both operator<<s non-member exhibits the ambiguity in all compilers (as expected)
After looking through the standard drafts (N3242 and N3690) I failed to find anything making member functions/operators better match than non-member ones.
So I failed to prove clang-3.4 is wrong and I wonder who's right.
Thus my question is:
Is this code valid? Should member operators/functions be better match than non-member ones and it's a bug in clang-3.4?
Or are all the other compilers wrong/too permissive?
I am aware that changing the second operator<< to non-templated function (with std::ostream instead of template parameter) would resolve the the ambiguity and work as expected, but that's not the point here.

Overload resolution adds an additional parameter to a member function just for the purpose of overload resolution:
[over.match.funcs]/2
The set of candidate functions can contain both member and non-member functions to be resolved against the same argument list. So that argument and parameter lists are comparable within this heterogeneous set, a member function is considered to have an extra parameter, called the implicit object parameter, which represents the object for which the member function has been called.
/4
For non-static member functions, the type of the implicit object parameter is
— “lvalue reference to cv X” for functions declared without a ref-qualifier or with the & ref-qualifier
— “rvalue reference to cv X” for functions declared with the && ref-qualifier
where X is the class of which the function is a member and cv is the cv-qualification on the member function declaration.
Some special rules follow, for example to allow binding an rvalue to this implicit object parameter (for calling member functions w/o ref-qualifier on rvalues, e.g. ostr{std::cout}<<"hello").
The function signatures including the implicit object parameter we need to compare for overload resolution are:
template<class T>
ostr& ostr::operator<<(ostr&, const T&); // F1
template<class Stream>
Stream& ::operator<<(Stream&, const xy&); // F2
After substitution for os << x, we get the same signature:
ostr& ostr::operator<<(ostr&, const xy&);
ostr& :: operator<<(ostr&, const xy&);
So only one of the "tie-breakers" in [over.match.best]/1 could resolve the ambiguity. Indeed, one could apply, namely the "F1 is more specialized than F2" (or vice versa): partial ordering of function templates.
N.B. The procedure of adding an implicit object parameter is specified again in the description of partial ordering [temp.func.order]/3.
For partial ordering of F1 and F2 (as defined above), we first create two unique types:
struct unique_T {};
struct unique_Stream {};
Then we transform F1 into F1' by replacing the template parameter T with the unique type unique_T (and similarly for F2):
ostr& ostr::operator<<(ostr&, const unique_T&);
ostr& :: operator<<(unique_Stream&, const xy&);
The parameters of the transformed function F1' are now used to try to deduce the template parameters of the untransformed F2:
ostr a0;
unique_T a1; // no reference, no cv-qualifier
::operator<<(a0, a1) // does template argument deduction succeed?
// reminder: signature of ::operator<<
template<class Stream>
Stream& ::operator<<(Stream&, const xy&);
The deduction succeeds for a0 [with Stream = ostr], therefore the type ostr& from F1 is considered to be at least as specialized as type of the corresponding first parameter of F2 (Stream&, with Stream being a template parameter). I'm not sure what happens to the second argument a1, since no deduction takes place for the second parameter of ::operator<< (it is of type const xy&).
Now we repeat the process with arguments from F2' and try to deduce the template parameters of F1:
unique_Stream a0;
xy a1;
ostr::operator<<(a0, a1);
// reminder: signature of ostr::operator<<
template<class T>
ostr& ostr::operator<<(ostr&, const T&);
Here, no deduction occurs for the first argument, but it occurs and succeeds for the second argument [with T = xy].
I conclude no function template is more specialized. Therefore overload resolution should fail due to ambiguity.

Related

std::variant converting constructor doesn't handle const volatile qualifiers

The code below:
int i = 1;
const int i_c = 2;
volatile int i_v = 3;
const volatile int i_cv = 4;
typedef std::variant<int, const int, volatile int, const volatile int> TVariant;
TVariant var (i );
TVariant var_c (i_c );
TVariant var_v (i_v );
TVariant var_cv(i_cv);
std::cerr << std::boolalpha;
std::cerr << std::holds_alternative< int>(var ) << std::endl;
std::cerr << std::holds_alternative<const int>(var_c ) << std::endl;
std::cerr << std::holds_alternative< volatile int>(var_v ) << std::endl;
std::cerr << std::holds_alternative<const volatile int>(var_cv) << std::endl;
std::cerr << var .index() << std::endl;
std::cerr << var_c .index() << std::endl;
std::cerr << var_v .index() << std::endl;
std::cerr << var_cv.index() << std::endl;
outputs:
true
false
false
false
0
0
0
0
coliru
And so std::variant converting constructor doesn't take into account const volatile qualifier of the converting-from type. Is it expected behavior?
Information about converting constructor from cppreference.com
Constructs a variant holding the alternative type T_j that would be selected by overload resolution for the expression F(std::forward<T>(t)) if there was an overload of imaginary function F(T_i) for every T_i from Types...
The problem is that in the case above the overload set of such imaginary function is ambiguous:
void F( int) {}
void F(const int) {}
void F( volatile int) {}
void F(const volatile int) {}
coliru
cppreference.com says nothing about this case. Does the standard specify this?
I'm making my own implementation of std::variant class. My implementation of converting constructor is based on this idea. And the result is the same as shown above (the first suitable alternative is selected, even though there are others). libstdc++ probably implements it in the same way, because it also selects the first suitable alternative. But I'm still wondering if this is correct behavior.
Yeah, this is just how functions work when you pass by value.
The function void foo(int) and the function void foo(const int) and the function void foo(volatile int) and the function void foo(const volatile int) are all the same function.
By extension, there is no distinction for your variant's converting constructor to make, and no meaningful way to use a variant whose alternatives differ only in their top-level cv-qualifier.
(Well, okay, you can emplace with an explicit template argument, as Marek shows, but why? To what end?)
[dcl.fct/5] [..] After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type. [..]
Note that you are creating copy of value. This means that const and volatile modifiers can be safely discarded. That is why template always deduces int.
You can force specific type using emplace.
See demo https://coliru.stacked-crooked.com/a/4dd054dc4fa9bb9a
My reading of the standard is that the code should be ill-formed due to ambiguity. It surprises me that both libstdc++ and libc++ appear to allow it.
Here's what [variant.ctor]/12 says:
Let T_j be a type that is determined as follows: build an imaginary function FUN(T_i) for each alternative type T_i. The overload FUN(T_j) selected by overload resolution for the expression FUN(std::forward<T>(t)) defines the alternative T_j which is the type of the contained value after construction.
So four functions are created: initially FUN(int), FUN(const int), FUN(volatile int), and FUN(const volatile int). These are all equivalent signatures, so they could not be overloaded with each other. This paragraph does not really specify what should happen if the overload set cannot actually be built. However, there is a note that strongly implies a particular interpretation:
[ Note:
variant<string, string> v("abc");
is ill-formed, as both alternative types have an equally viable constructor for the argument. —end note]
This note is basically saying that overload resolution cannot distinguish between string and string. In order for that to happen, overload resolution must be done even though the signatures are the same. The two FUN(string)s are not collapsed into a single function.
Note that overload resolution is allowed to consider overloads with identical signatures due to templates. For example:
template <class T> struct Id1 { using type = T; };
template <class T> struct Id2 { using type = T; };
template <class T> void f(typename Id1<T>::type x);
template <class T> void f(typename Id2<T>::type x);
// ...
f<int>(0); // ambiguous
Here, there are two identical signatures of f, and both are submitted to overload resolution but neither is better than the other.
Going back to the Standard's example, it seems that the prescription is to apply the overload resolution procedure even if some of the overloads could not be overloaded with each other as ordinary function declarations. (If you want, imagine that they are all instantiated from templates.) Then, if that overload resolution is ambiguous, the std::variant converting constructor call is ill-formed.
The note does not say that the variant<string, string> example was ill-formed because the type selected by overload resolution occurs twice in the list of alternatives. It says that the overload resolution itself was ambiguous (because the two types had equally viable constructors). This distinction is important. If this example were rejected after the overload resolution stage, an argument could be made that your code is well-formed since the top-level cv-qualifiers would be deleted from the parameter types, making all four overloads FUN(int) so that T_j = int. But since the note suggests a failure during overload resolution, that means your example is ambiguous (as the 4 signatures are equivalent) and this must be diagnosed.

Overload resolution, templates and inheritance

#include <iostream>
struct A {};
struct B : public A {};
template<typename T>
void foo(const T &x) { std::cout << "Called template" << std::endl; }
void foo(const A &a) { std::cout << "Called A" << std::endl; }
int main()
{
foo(A());
foo(B());
return 0;
}
This prints:
Called A
Called template
I was under the impression that a suitable non-template function would always be chosen over a template function. Can someone explain to me the resolution steps that lead to this somewhat surprising result?
I was under the impression that a suitable non-template function would always be chosen over a template function.
This only holds if the template and the non-template are equally good candidates. That's why the non-template is chosen for foo(A()).
However, in the case of foo(B()), using the non-template requires a derived-to-base conversion. So the function template is strictly better, and hence it's chosen.
The foo template instantiates into void foo(const B&). Consider what it would look like without templates:
void foo(const B &x) { std::cout << "Called template" << std::endl; }
void foo(const A &a) { std::cout << "Called A" << std::endl; }
I believe you'll agree calling foo(B()) should unambiguously pick the first one. That's exactly why the template is chosen.
n3376 13.3.3.1/6
When the parameter has a class type and the argument expression has a
derived class type, the implicit conversion sequence is a
derived-to-base Conversion from the derived class to the base class.
n3376 13.3.3.1/8
If no conversions are required to match an argument to a parameter
type, the implicit conversion sequence is the standard conversion
sequence consisting of the identity conversion (13.3.3.1.1).
Identity conversion has exact match rank due table in 13.3.3.1.1/table 12, but derived-to-base is worse, than identity.
So, compiler just have candidates in first case
// template after resolving
void foo(const A&)
// non-template
void foo(const A&)
Both has identity rank, but since first is function-template, second will be chosen.
And in second case
// template after resolving
void foo(const B&)
// non-template
void foo(const A&)
Only first has identity rank and will be chosen.
Can someone explain to me the resolution steps that lead to this somewhat surprising result?
you may look at Overload Resolution at cppreference.com:
http://en.cppreference.com/w/cpp/language/overload_resolution
in particular see the section Ranking of implicit conversion sequences
Extension of the Answer:
I tried to provide more clarification with an excerpt of the information from the aforementioned link:
A function template by itself is not a type, or a function, or any other entity. No code is generated from a source file that contains only template definitions. In order for any code to appear, a template must be instantiated: the template arguments must be determined so that the compiler can generate an actual function (or class, from a class template).
For that, the compiler goes through:
function template name lookup
template argument deduction
Down to here, the compiler has a couple of candidate function definitions which can handle the specific function call. These candidates are instannces of the template function as well as relevant non-template function definitions in the program.
But the answer to your question lies in fact here:
Template argument deduction takes place after the function template name lookup (which may involve argument-dependent lookup) and before overload resolution.
The fact that function overload resolution is performed after template function instantiation is the reason for the ouput of your code.
Now your specific case goes through overload resolution as the following:
Overload Resolution:
If the [previous] steps produce more than one candidate function, then overload resolution is performed to select the function that will actually be called. In general, the candidate function whose parameters match the arguments most closely is the one that is called.
.
.
.
...
F1 is determined to be a better function than F2 if implicit conversions for all arguments of F1 are not worse than the implicit conversions for all arguments of F2, and
1) there is at least one argument of F1 whose implicit conversion is better than the corresponding implicit conversion for that argument of F2
...
.
.
.
Ranking of implicit conversion sequences:
Each type of standard conversion sequence is assigned one of three ranks:
1) Exact match: no conversion required, lvalue-to-rvalue conversion, qualification conversion, user-defined conversion of class type to the same class
2) Promotion: integral promotion, floating-point promotion
3) Conversion: integral conversion, floating-point conversion, floating-integral conversion, pointer conversion, pointer-to-member conversion, boolean conversion, user-defined conversion of a derived class to its base
The rank of the standard conversion sequence is the worst of the ranks of the standard conversions it holds (there may be up to three conversions)
Binding of a reference parameter directly to the argument expression is either Identity or a derived-to-base Conversion:
struct Base {};
struct Derived : Base {} d;
int f(Base&); // overload #1
int f(Derived&); // overload #2
int i = f(d); // d -> Derived& has rank Exact Match
// d -> Base& has rank Conversion
// calls f(Derived&)

Universal references and std::initializer_list

In his "C++ and Beyond 2012: Universal References" presentation, Scott repeatedly stresses the point, that universal references handle/bind to everything and thus overloading a function that already takes a universal reference parameter does not make sense.
I had no reason to doubt that until I mingled them with std::initializer_list.
Here is a short example:
#include <iostream>
#include <initializer_list>
using namespace std;
template <typename T>
void foo(T&&) { cout << "universal reference" << endl; }
template <typename T>
void foo(initializer_list<T>) { cout << "initializer list" << endl; }
template <typename T>
void goo(T&&) { cout << "universal reference" << endl; }
template <typename T>
void goo(initializer_list<T> const&) { cout << "initializer list" << endl; }
int main(){
auto il = {4,5,6};
foo( {1,2,3} );
foo( il );
goo( {1,2,3} );
goo( il );
return 0;
}
Oddly enough, VC11 Nov 2012 CTP complains about ambiguity (error C2668: 'foo' : ambiguous call to overloaded function). Yet even more suprising is, that gcc-4.7.2, gcc-4.9.0 and clang-3.4 agree on the following output:
initializer list
initializer list
initializer list
universal reference
So apparently it is possible (with gcc and clang) to overload functions taking universal references with initializer_lists but when using the auto + { expr } => initializer_list-idiom it does even matter whether one takes the initializer_list by value or by const&.
At least to me that behavior was totally surprising.
Which behavior conforms to the standard? Does anyone know the logic behind that?
Here's the crux: Deducing a type from a braced-init-list ({expr...}) doesn't work for template arguments, only auto. With template arguments, you get a deduction failure, and the overload is removed from consideration. This leads to the first and third output.
it does even matter whether one takes the initializer_list by value or by const&
foo: For any X, two overloads taking X and X& parameters are ambiguous for an lvalue argument - both are equally viable (same for X vs X&& for rvalues).
struct X{};
void f(X);
void f(X&);
X x;
f(x); // error: ambiguous overloads
However, partial ordering rules step in here (§14.5.6.2), and the function taking a generic std::initializer_list is more specialized than the generic one taking anything.
goo: For two overloads with X& and X const& parameters and a X& argument, the first one is more viable because the second overload requires a Qualification conversion from X& to X const& (§13.3.3.1.2/1 Table 12 and §13.3.3.2/3 third sub-bullet).
If Scott really says that he's wrong, and it's another problem with the misleading "universal references" mental model he's teaching.
So-called "universal references" are greedy, and might match when you don't want or expect them to, but that doesn't mean they are always the best match.
Non-template overloads can be an exact match and will be preferred to the "universal reference", e.g. this selects the non-template
bool f(int) { return true; }
template<typename T> void f(T&&) { }
bool b = f(0);
And template overloads can be more specialized than the "universal reference" and so will be chosen by overload resolution. e.g.
template<typename T> struct A { };
template<typename T> void f(T&&) { }
template<typename T> bool f(A<T>) { return true; }
bool b = f(A<int>());
DR 1164 confirms that even f(T&) is more specialized than f(T&&) and will be preferred for lvalues.
In two of your cases the initializer_list overloads are not only more specialized, but a braced-init-list such as {1,2,3} can never be deduced by template argument deduction.
The explanation for your results is:
foo( {1,2,3} );
You cannot deduce a template argument from a braced-init-list, so deduction fails for foo(T&&) and foo(initializer_list<int>) is the only viable function.
foo( il );
foo(initializer_list<T>) is more specialized than foo(T&&) so is chosen by overload resolution.
goo( {1,2,3} );
You cannot deduce a template argument from a braced-init-list, so goo(initializer_list<int>) is the only viable function.
goo( il );
il is a non-const lvalue, goo(T&&) can be called with T deduced as initializer_list<int>&, so its signature is goo(initializer_list<int>&) which is a better match than goo(initializer_list<int> const&) because binding the non-const il to a const-reference is a worse conversion sequence than binding it to a non-const-reference.
One of the comments above quotes Scott's slides as saying: "Makes no sense: URefs handle everything." That's true, and that's exactly why you might want to overload! You might want a more specific function for certain types, and the universal reference function for everything else. You can also use SFINAE to constrain the universal reference function to stop it handling certain types, so that other overloads can handle them.
For an example in the standard library, std::async is an overloaded function taking universal references. One overload handles the case where the first argument is of type std::launch and the other overload handles everything else. SFINAE prevents the "everything else" overload from greedily matching calls that pass std::launch as the first argument.
Ok, so first the reaction to foo makes sense. initializer_list<T> match both calls and is more specialized, therefore should be called this way.
For goo, this is in sync with perfect forwarding. when calling goo(il), there is the choice between goo(T&&) (with T = initializer_list<T>&) and the constant reference version. I guess calling the version with the non-const reference has precedence over the more specialized version with the const reference. That being said, I am not sure this is a well defined situation w.r.t. the standard.
Edit:
Note that if there were no template, that would be resolved by the paragraph 13.3.3.2 (Ranking implicit conversion sequences) of the standard. The problem here is that, AFAIK, the partial ordering of template function would dictate the second (more specialized) goo(initializer_list<T> const&) is to be called, but the ranking on implicit conversion sequences would dictate that goo(T&&) is to be called. So I guess this is an ambiguous case.

Overloading conversion operator template

Consider the following simple example
struct C
{
template <typename T> operator T () {return 0.5;}
operator int () {return 1;}
operator bool () {return false;}
};
int main ()
{
C c;
double x = c;
std::cout << x << std::endl;
}
When compiled with Clang, it gives the following error
test.cpp:11:12: error: conversion from 'C' to 'double' is ambiguous
double x = c;
^ ~
test.cpp:4:5: note: candidate function
operator int () {return 1;}
^
test.cpp:5:5: note: candidate function
operator bool () {return false;}
^
test.cpp:3:27: note: candidate function [with T = double]
template <typename T> operator T () {return 0.5;}
^
1 error generated.
Other compilers generate similar errors, e.g., GCC and Intel iclc
If I remove operator int and operator bool. It compiles fine and work as expected. If only remove one of them, that is keep the template operator and say operator int, then the non-template version is always chosen.
My understanding is that only when the template and non-template overloaded functions are equal in the sense that they are both perfect match or both require the same conversion sequence, the non-template version will be preferred. However in this case, it appears that the compiler does not see the operator template as a perfect match. And when both the bool and int overloading are present, then naturally it considers they are ambiguous.
In summary, my question is that why the operator template is not considered a perfect match in this case?
Let's break this down into two different problems:
1. Why does this generate a compiler error?
struct C
{
operator bool () {return false;}
operator int () {return 1;}
};
As both int and bool can be implicitly converted to double, the compiler can not know which function it should use. There are two functions which it could use and neither one takes precedence over the other one.
2. Why isn't the templated version a perfect match?
struct C
{
template <typename T> operator T () {return 0.5;}
operator int () {return 1;}
};
Why is operator int() called when requesting a double?
The non-template function is called because a non-template function takes precedence in overload resolution. (Overloading function templates)
EDIT:
I was wrong! As Yan Zhou mentioned in his comment, and as it is stated in the link I provided, a perfect match in the templated function takes precedence over the non-templated function.
I tested your code (compiled with g++ 4.7.2), and it worked as expected: it returned 0.5, in other words, the templated function was used!
EDIT2:
I now tried with clang and I can reproduce the behaviour you described. As it works correctly in gcc, this seems to be a bug in clang.
This is interesting. There are two ways to read a critical part of section 13.3.3. The original example should definitely call the function template, but the version where one of the non-templates is removed might be argued to be ambiguous.
13.3.3:
A viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICS_i(F1) is not a worse conversion sequence than ICS_i(F2), and then
for some argument j, ICS_j(F1) is a better conversion sequence than ICS_j(F2), or, if not that,
the context is an initialization by user-defined conversion (see 8.5, 13.3.1.5, and 13.3.1.6) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type, or, if not that,
F1 is a non-template function and F2 is a function template specialization, or, if not that,
F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.6.2.
If there is exactly one viable function that is a better function than all other viable functions, then it is the one selected by overload resolution; otherwise the call is ill-formed.
In the example, clang correctly identifies the set of three viable candidate functions:
C::operator int()
C::operator bool()
C::operator double<double>()
The third is a function template specialization. (I don't think the syntax above is legal, but you get the idea: at this point of overload resolution it's not treated as a template, but as a specialization with a definite function type.)
The only Implicit Conversion Sequence on arguments here (ICS1) is the exact match "lvalue C" to "C&" on the implicit parameter, so that won't make a difference.
This example is exactly the situation described in the second bullet, so the function returning double is clearly better than the other two.
Here's where it gets weird: By a very literal reading, operator int is also better than the template specialization, because of the third bullet. "Wait a minute, shouldn't 'better than' be antisymmetric? How can you say F1 is better than F2 AND F2 is better than F1?" Unfortunately, the Standard doesn't explicitly say anything of the sort. "Doesn't the second bullet take priority over the third bullet because of the 'if not that' phrase?" Yes, for constant F1 and F2. But the Standard doesn't say that satisfying the second bullet for (F1,F2) makes the third bullet for (F2,F1) not applicable.
Of course, since operator int is not better than operator bool and vice versa, there is still "exactly one viable function that is a better function than all other viable functions".
I'm not exactly endorsing this weird reading, except maybe to report it as a Standard defect. Going with that would have bizarre consequences (like removing an overload which was not the best from this example changes a program from well-formed to ambiguous!). I think the intent is for the second bullet to be considered both ways before the third bullet is considered at all.
Which would mean the function template should be selected by overload resolution, and this is a clang bug.

Global function template overloading and const parameters

If I compile (gcc 4.6.0) and run this code:
#include <iostream>
template <typename T> void F(/* const */ T& value) {
std::cout << "T & " << value << std::endl;
}
template <typename T> void F(/* const */ T* value) {
std::cout << "T * " << value << std::endl;
F(*value);
}
int main(int argc, char* argv[]) {
float f = 123.456;
float* pf = &f;
F(pf);
return 0;
}
I get the following output:
T * 0x7fff7b2652c4
T & 123.456
If I uncomment the const keywords I get the following output:
T & 0x7fff3162c68c
I can change float* pf = &f; to const float* pf = &f; to get the original output again, that's not the issue.
What I'd like to understand is why, when compiling with the const modifiers, overload resolution considers const T& value a better match than const T* valuefor a non-const float*?
During overload resolution, overloads requiring no conversions beat overloads requiring some conversions, even if those conversions are trivial. Quoting the C++03 standard, [over.match.best] (§13.3.3/1):
Define ICSi(F) as follows:
if F is a static member function, ICS1(F) is defined such that ICS1(F) is neither better nor worse than ICS1(G) for any function G, and, symmetrically, ICS1(G) is neither better nor worse than ICS1(F); otherwise,
let ICSi(F) denote the implicit conversion sequence that converts the i-th argument in the list to the type of the i-th parameter of viable function F. 13.3.3.1 defines the implicit conversion sequences and 13.3.3.2 defines what it means for one implicit conversion sequence to be a better conversion sequence or worse conversion sequence than another.
Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,
F1 is a non-template function and F2 is a function template specialization, or, if not that,
F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.5.2, or, if not that,
the context is an initialization by user-defined conversion (see 8.5, 13.3.1.5, and 13.3.1.6) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type.
When const is present, in order to call the overload taking a reference, no conversion is necessary -- T is deduced to be float* and the argument is float* const&. However, in order to call the overload taking a pointer, float would need to be converted to float const for said overload to be viable. Consequently, the overload taking a reference wins.
Note, of course, that if pf were changed to be a float const*, the behavior would go back to the way you expected because the overload taking a pointer would no longer require a conversion.