J
James Kanze
My statement may have made more sense if I used the correct function
name - toupper! Somehow I made this mistake.
A yes. So there's both a function template and overloading for
the compiler to contend with.
And by arranging it to be a non-template class type, we delay
overload resolution until the function is called?
Overload resolution always occurs at the call site. The problem
here isn't overload resolution---it's template type deduction.
If the fourth argument is an overload set which contains a
function template, the compiler cannot do type deduction---it
needs to know the target type to do type deduction on the
function template, and it needs the exact type of the function
in order to do type deduction for std::transform. There's a
cyclic dependency. If the fourth argument is an overloaded
function, even without a template, the compiler still needs to
know the target type to do overload resolution, and it needs the
results of the overload resolution to do argument deduction for
std::transform (and thus determine the target type).
When we pass a functional object, we specify an exact type---the
type of the object. This breaks the cycle in the dependencies:
the type of the argument is fixed; the compiler does not have to
deduce or resolve it. This is true regardless of whether the
functional argument is a template or not---it is an object, it
has a fixed type, and there is no possible overloading or
automatic type deduction. There is no automatic type deduction
for class templates or objects. Only for functions. Thus, for
example, if I create a ToUpper template class:
template< typename charT >
class ToUpper
{
public:
explicit ToUpper( std::locale const& l = std::locale() )
: myLocale( l )
{( l ) )
}
charT operator()( charT ch ) const
{
return myCtype->toupper( ch ) ;
}
private:
std::locale myLocale ;
std::ctype< charT > const*
myCtype ;
} ;
I would have to explicitly specify the type in order to use it:
std::transform( s.begin(), s.end(), s.begin(),
ToUpper< char >() ) ;
And having explicitly specified the type, the compiler no longer
has any argument deduction or overload resolution to do, and the
cycle is broken.