Re: Terminology in english :)
On Mar 19, 1:53 pm, Taras_96 <taras...@gmail.com> wrote:
I think I understand what you're saying now, but I still don't
understand how the dependance is cyclical.
The compiler needs to know the type of the function argument of
std::transform in order to do type deduction on std::tolower
(and thus determine its type), and it need to know the type of
std::tolower in order to do type deduction for the function
argument of std::transform. You can break the cycle by
specifying one or the other:
std::transform< std::string::iterator,
std::string::iterator,
int (*)( int ) >
( s.begin(), s.end(), s.end(), std::tolower ) ;
or
std::transform(
( s.begin(), s.end(), s.end(),
static_cast< int(*)( int ) >( std::tolower ) ) ;
(The first would be a lot easier to use if the type of the
function were the first template argument of std::transform, and
not the last.)
(And obviously, these are just examples to clarify the
situation. The actual call of std::toupper in the above would
result in undefined behavior unless you've previously ensured
that all elements in the string have non-negative values.)
I've tried to recreate a similar situatino in some artificial
code below.
callThisFunction is loosely equivalent to transform X
parameter is supposed to be equivalent to toupper (a function
pointer)
I assume that toupper receives the characters to transfrom
from the iterators. This is the purpose of the Y parameter -
it is going to be input into the X function
TEST CODE:
#include <iostream>
using namespace std;
template <class X, class Y> void callThisFunc(X x, Y y)
{
x(y);
}
template <class X> void templatedUselessFunction(X x)
{
cout << "templated useless function: " << x << endl;
}
void overloadedFunction(char c)
{
cout << "in char function: " << c << endl;
}
void overloadedFunction(int x)
{
cout << "in int function: " << x << endl;
}
----------END CODE----------
Let's consider the overloaded functions first
As you mentioned,
On Mar 18, 6:18 pm, James Kanze <james.ka...@gmail.com> wrote:
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).
callThisFunc(overloadedFunction,51234);
The type X can not be deduced for callThisFunc because the
function is overloaded. Even though obviously at the point
where the fucntion is called, the version of the function to
call is unambiguous, at the point callThisFunc is called the
type X is unknown, and thus automatic template type deduction
can't be done (even though the version of the function to call
is not indeterminate - we intend to call the int version). We
can disambiguate the type of the argument by using a cast-like
syntax (even though, as explained earlier, it isn't a case).
callThisFunc((void(*)(int))overloadedFunction,51234);
This however forces us to explicitly specify the function, and
thus we lose the advantage of having overloaded functions in
the first place. Alternatively we could wrap
overloadedFunction into a functor, and use this instead.
Now, onto the templated function
callThisFunc(templatedUselessFunction,3);
This won't work because at the point the function is called,
the type of X can not be determined (similar to the overloaded
function case), even though again the call is ultimately
unambiguous (if the compiler could look ahead into how the
templated function is used.....). Again, similar to the
overloaded function case, we can explicitly specify the type
of the argument:
Correct. Strictly speaking, the error doesn't occur during
overload resolution per se, but because type deduction fails.
Type deduction can fail in two ways: if no function can be
deduced, then no instantiation of the template function is added
to the overload set, and the compiler continues, considering the
other possible overloads. If the deduction is ambiguous,
however, as it is here, and can give more than one result, it is
an error.
For the user, of course, it comes out to pretty much the same
thing. You can sort of think of a function template as an
infinite set of overloads. (It's not quite the same thing,
because the compiler considers a much smaller set of possible
implicit conversions when doing template argument deduction than
it does when doing function overload resolution.)
callThisFunc(templatedUselessFunction<int>,3);
I don't understand, however, how this is a cylical dependancy
This isn't. In fact, this should work, since there is only one
possible 'templatedUselessFunction<int>. Drop the <int>,
however, and the compiler needs to know the results of argument
deduction on callThisFunc, in order to deduce the type of
templatedUselessFunction, and it needs to know the type of
templatedUselessFunction, in order to do argument deduction on
callThisFunc. Specify the template argument of
templatedUselessFunction (or which function to choose from an
overload set), and you break the dependency. Specifying the
type of the first parameter of callThisFunc also words, e.g.:
callThisFunc< void (*)( int ) >( templatedUselessFunction, 3) ;
- callThisFunc requires to know the type of X, the type of X
is not known because it is a templated function - the type of
the templated function does not depend on callThisFunc (well,
to me anyway).
In the case of 'toupper', to upper is both a templated
function and an overloaded function, so it's a bit of both
situations.
Yes, but it fails because the template argument deduction is
ambiguous. (If somehow the template argument deduction could be
made to work, without forcing the use of the template function,
it would fail because of the overloaded function.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34