The reason is that the compiler has two overloads to choose from each of which takes three parameters. Note that during argument deduction process, the compiler deduces participating template parameters from function call arguments indepdently looking at the parameter/argument pair.
Argument deduction succeeds only when the template parameters are determined unambiguously looking at each parameter/argument pair. This means, that while looking at your second parameter/argument pair, it does (and cannot) rely on the fact that atype1, atype2 and atype3 each are of type 'int', even if you rearrange the template parameters as
template<class type, class ret, class atype1, class atype2, class atype3>
ret call3(type *pClass, atype1 arg, atype2 arg2, atype3 arg3, ret(type::* funcptr)(atype1, atype2, atype3))
{
//do some stuff here
return (pClass->*funcptr)(arg, arg2, arg3);
}
Here's the quote from the Standard that supports this:
The non-deduced contexts are:
— The
nested-name-specifier of a type that
was specified using a qualified-id.
—
A non-type template argument or an
array bound in which a subexpression
references a template parameter.
— 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.
— A
function parameter for which argument
deduction cannot be done because the
associated function argument is a
function, or a set of overloaded
functions (13.4), and one or more of
the following apply:
— more than one
function matches the function
parameter type (resulting in an
ambiguous deduction),or
— no function
matches the function parameter type,
or
— the set of functions supplied as
an argument contains one or more
function templates.
Now for the solution,
I think the only solution is that you will have to explicitly specify the template parameters rather than relying on template argument deduction. A little rearrangement of the template parameters will help
template<class atype1, class atype2, class atype3, class type, class ret>
ret call3(type *pClass, ret(type::* funcptr)(atype1, atype2, atype3), atype1 arg, atype2 arg2, atype3 arg3)
{
//do some stuff here
return (pClass->*funcptr)(arg, arg2, arg3);
}
int main(){
MyClass *a = new MyClass();
call3<int, int, int>(a, &MyClass::test, 1, 2, 3);
}