overload resolution in templates - c++

Any one Explain this with an example
"Involving conversions on a function argumentsinvolved in template
parameter deduction."
EXamples like this:
template<class T> struct B { /* ... */ };
template<class T> struct D : public B<T> { /* ... */ };
template<class T> void f(B<T>&);
void g(B<int>& bi, D<int>& di)
{
f(bi);
f(di);
}
Please give me some more examples
EDIT: It is a point / statement from ISO C++ Standard 14.8.3/5th :Overload resolution

It is about what the example shows. In sum, these are those conversions
The function parameter can be a Base<T>, while the function argument is a Derived<T>. Compare with ifstream << "hello" - left side of operator<< is deduced in that way.
The function parameter can be a const U&, while the function argument is a U (same for volatile).
The function parameter can be a const U* or const E C::* while the function argument is a U* or E C::* respectively (these are the qualification conversions) - same for volatile.
Other conversions cannot be done for a function parameter / argument that participate in deduction. The whole range of conversions can be applied if a function parameter does not participate in deduction, but this needs a non-deduced context or a context where there is no argument to be deduced at all, and implementation don't actually agree on it (see here).
In other words:
template<typename T> struct id { typedef T type; };
template<typename T> void f(T, typename id<T>::type);
int main() {
// deduction acts on void(int*, int*) - deduction does not need
// to deduce anything and follows [temp.arg.explicit]p4
f<int*>(0, 0);
// deduction acts on void(T, id<T>::type) - second is a non-deduced context,
// which *will* allow the conversion of int -> int*, since it will not compare
// the argument with parameter during deduction (since it is non-deduced).
f((int*)0, 0);
}
The second example is vital for some partial ordering contexts to work.

Related

Why sometimes calling template function needs angle bracket and full type specification and sometimes not? [duplicate]

// Function declaration.
template <typename T1,
typename T2,
typename RT> RT max (T1 a, T2 b);
// Function call.
max <int,double,double> (4,4.2)
// Function call.
max <int> (4,4.2)
One case may be when you need to specify the return type.
Is there any other situation which requires the argument types to be specified manually?
(1) When there is no argument to the function and still it's a template type, then you may have to specify the arguments explicitly
template<typename T>
void foo ()
{}
Usage:
foo<int>();
foo<A>();
(2) You want to distinguish between value and reference.
template<typename T>
void foo(T obj)
{}
Usage:
int i = 2;
foo(i); // pass by value
foo<int&>(i); // pass by reference
(3) Need another type to be deduced instead of the natural type.
template<typename T>
void foo(T& obj)
{}
Usage:
foo<double>(d); // otherwise it would have been foo<int>
foo<Base&>(o); // otherwise it would have been foo<Derived&>
(4) Two different argument types are provided for a single template parameter
template<typename T>
void foo(T obj1, T obj2)
{}
Usage:
foo<double>(d,i); // Deduction finds both double and int for T
If the function template parameter appears in the function parameter list, then you don't need to specify the template parameters. For example,
template<typename T>
void f(const T &t) {}
Here T is a template parameter, and it appears in the function parameter list, i.e const T &t. So you don't need to specify the template parameter when calling this function:
f(10); //ok
Since the type of 10 is int, so the compiler can deduce the template parameter T from it, and T becomes int.
Note that since the type deduction is done from using the information of the function arguments, its called template argument deduction. Now read on.
If the template parameter doesn't appear in the function parameter list, then you have to provide the template parameter. Example:
template<typename T>
void g(const int &i) {}
Notice g() is different from f(). Now T doesn't appear in the function parameter list. So:
g(10); //error
g<double>(10); //ok
Note that if a function template templatizes on the return type as well, and the return type is different from the types appearing the function parameter list, then you've to provide the return type:
template<typename T>
T h(const T &t) {}
Since return type T is same as the function parameter, type deduction is possible from function argument:
h(10); //ok - too obvious now
But if you've this:
template<typename R, typename T>
R m(const T &t) {}
Then,
m(10); //error - only T can be deduced, not R
m<int>(10); //ok
Note that even though the function template m has templatized on two types : R and T, we've provided only ONE type when calling it. That is, we've written m<int>(10) as opposed to m<int,int>(10). There is no harm in writing the later, but its okay, if you don't. But sometimes you've to specif both, even if one type T can be deduced. It is when the order of type parameters is different as shown below:
template<typename T, typename R> //note the order : its swapped now!
R n(const T &t) {}
Now, you've to provide both types:
n(10); //error - R cannot be deduced!
n<int>(10); //error - R still cannot be deduced, since its the second argument!
n<int,int>(10); //ok
The new thing here is : the order of type parameters is also important.
Anyway, this covers only the elementary concept. Now I would suggest you to read some good book on templates, to learn all the advanced things regarding type deduction.
In general, you need to explicitly specify the types when the compiler can't figure it out on its own. As you mentioned, this often happens when the return type is templatized, since the return type cannot be inferred from the function call.
Template classes have the same problem -- instantiating a std::vector offers no way for the compiler to determine what type your vector is storing, so you need to specify std::vector<int> and so forth.
The type resolution is only performed in the case of function arguments, so it may be easier to view that as the special case; ordinarily, the compiler is unable to guess what type(s) to use.
The simple answer is that you need to provide the types when the compiler cannot deduce the types by itself, or when you want the template to be instantiated with a particular type that is different from what the compiler will deduce.
There are different circumstances when the compiler cannot deduce a type. Because type deduction is only applied to the arguments (as is the case with overload resolution) if the return type does not appear as an argument that is deducible, then you will have to specify it. But there are other circumstances when type deduction will not work:
template <typename R> R f(); // Return type is never deduced by itself
template <typename T>
T min( T const & lhs, T const & rhs );
min( 1, 2 ); // Return type is deducible from arguments
min( 1.0, 2 ); // T is not deducible (no perfect match)
min<double>( 1.0, 2 ); // Now it is ok: forced to be double
min<double>( 1, 2 ); // Compiler will deduce int, but we want double
template <typename T>
void print_ptr( T* p );
print_ptr<void>( 0 ); // 0 is a valid T* for any T, select manually one
template <typename T>
T min( T lhs, T rhs );
int a = 5, b = 7;
min<int&>(a,b)++; // Type deduction will drop & by default and call
// min<int>(a,b), force the type to be a reference
template <typename C>
typename C::value_type
min_value( typename C::const_iterator begin, typename C::const_iterator end );
std::vector<int> v;
min_value<std::vector<int> >( v.begin(), v.end() );
// Argument type is not deducible, there are
// potentially infinite C that match the constraints
// and the compiler would be forced to instantiate
// all
There are probably more reasons for an argument type cannot be deduced, you can take a look at §14.8.2.1 in the standard for the specifics of deduction of arguments from a function call.

Template parameters of function type with auto return type arguments of previous template parameter types

I have a template with two parameters: the first is a type, and the second is a function pointer with an argument whose type is the first template parameter. This MCVE works:
void returnsVoid(int x) { }
template <typename T, void (*Func)(T)>
struct foo { void bar(T t) { Func(t); } };
int main(int, char *[]) {
foo<int, returnsVoid> a; // ok
}
However, when I change the return type of the second template parameter to auto (as explained in this related question), I get an error:
void returnsVoid(int x) { }
template <typename T, auto (*Func)(T)>
struct foo {
void bar(T t) { Func(t); }
};
int main(int, char *[]) {
foo<int, returnsVoid> a; // error: unable to deduce ‘auto (*)(T)’ from ‘returnsVoid’
// note: mismatched types ‘T’ and ‘int’
}
Why does this no longer work with an auto return type?
I'm using g++ 9.3.0 on an Ubuntu Linux machine. A similar error occurs in clang 10.
This is gcc's bug. (Bug 83417)
It seems gcc failing deducing the type of auto when using the 1st template parameter T as function parameter; you can use std::type_identity (since C++20) to exclude it from participating in template argument deduction.
// workaround for gcc
template <typename T, auto (*Func)(std::type_identity_t<T>)>
struct foo {
void bar(T t) { Func(t); }
};
LIVE
BTW: Clang 10 seems working well.
All standard references below refer, unless noted otherwise, to N4861 (March 2020 post-Prague working draft/C++20 DIS).
TL;DR;
Jump to the A workaround to mitigate the GCC bug section in the bottom of this post for a workaround, accepted by GCC and Clanng, which still relies of deduction of dependent types to avoid a client having to specify a second template argument for the actual type of the function parameter associated with the "main" template argument; namely the function pointer used associated non-type template parameter.
Standardese
As per [temp.deduct.type]/13:
When the value of the argument corresponding to a non-type template
parameter P that is declared with a dependent type is deduced from
an expression, the template parameters in the type of P are deduced
from the type of the value. [ Example:
template<long n> struct A { };
template<typename T> struct C;
template<typename T, T n> struct C<A<n>> {
using Q = T;
};
using R = long;
using R = C<A<2>>::Q; // OK; T was deduced as long from the
// template argument value in the type A<2>
— end example ]
any dependent types in the declaration of a non-type template parameter that undergoes type deduction (from an expression) shall also be deduced from the associated argument for the non-type template parameter. It is also essential that [temp.deduct.type]/5, covering the non-deduced contexts, does not apply for general uses of dependent types within non-type template parameters that are function pointers; meaning in the OP's example, T is a dependent type and is thus deduced from the value of the argument to the non-type (function pointer) template parameter.
A common problem when a given, say, type template parameter is deduced from more than one source (e.g. as in the example of OP), is that deduction yields different types; e.g. as showing in the following blog post:
template<typename T>
struct Foo { T t; };
template<typename T>
void addToFoo(Foo<T>& foo, T val) { foo.t += val; }
int main() {
Foo<long> f{42};
addToFoo(f, 13); // error: no matching function for call to 'addToFoo'
// note: candidate template ignored: deduced conflicting
// types for parameter T (long vs. int).
return 0;
}
As has been shown in #songyuanyao: answer (and as is shown also in the blog post), a type identity transformation trait can be used to intentionally place a given template parameter in a non-deduced context for cases where several deduction sources yields conflicting results.
However, the root cause of OP:s failure is not conflicting deduction results (this is a red herring), but rather GCC:s failure to correctly deduce template parameter from when another template parameter is deduced, where the former is present as a dependent type.
Thus, if we go back to [temp.deduct.type]/13, for the following class template and subsequent partial specialization:
// #1
template <auto>
struct A { static void dispatch() = delete; };
// #2
template <typename T, void (*fun)(T)>
struct A<fun> {
static void dispatch() {
T t{};
fun(t);
}
};
the following:
A<f>::dispatch(); // #3
is well-formed if f is a function with a single argument (of a type that is default-constructible) which returns void, e.g.
void f(int) { std::cout << "void f(int)\n"; }
// -> #3 is well-formed
as this will match the partial specialization at #2, deducing T to int and the non-type template parameter (which decides the specialization blueprinted by the primary template), which is dependent on T in this partial specialization, to void(*)(int).
On the other hand, #3 is ill-formed if f does not return void, as the partial specialization at #2 is no longer viable.
void f(int) { std::cout << "int f(int)\n"; }
// -> #3 is ill-formed
The key here is that:
the partial specialization at #2 applies only for template arguments to A which match the second (non-type) template parameter of the specialization, and
the first template parameter of the specialization,T, is deduced from the deduction of the second (non-type) template parameter, as T is a dependent type in the declaration of the second template parameter.
Both GCC and Clang works as expected for the two cases above.
Now, if we consider the similar example as to that of #1 and #2 above:
// #4
template <auto>
struct B { static void dispatch() = delete; };
// #5
template <typename T, auto (*fun)(T)>
struct B<fun> {
static void dispatch() {
T t{};
fun(t);
}
};
// ... elsewere
// #6
B<f>::dispatch();
the same argument as above applies:
if template argument f refers to a function (now with less restrictions) that has a single argument (of a type that is default-constructible), then the partial specialization at #5 is viable, and its second non-type template parameter, which contains its first type template parameter as a dependent type, shall be used to deduce the latter.
The significant difference in this case is that the type of the non-type template parameter itself undergoes [temp.arg.nontype]/1:
If the type T of a template-parameter contains a placeholder type
([dcl.spec.auto]) or a placeholder for a deduced class type
([dcl.type.class.deduct]), the type of the parameter is the type
deduced for the variable x in the invented declaration
T x = template-argument ;
If a deduced parameter type is not permitted for a template-parameter
declaration ([temp.param]), the program is ill-formed.
but [temp.deduct.type]/13 still applies the same, and we may not that [temp.deduct.type]/13 was actually added as part of P0127R2 (Declaring non-type template parameters with auto) which introduced placeholder types for non-type template parameters for C++17.
Thus, the core issue is that GCC fails to perform dependent type deduction (as specified in [temp.deduct.type]/13) when the non-type template parameter in whose declaration the dependent type (to be deduced) is present is a function pointer (or, as shown in the linked to GCC bug report, as pointer to member) AND the non-type template parameter is declared with a placeholder type (auto).
#songyuanyao: answer shows a workaround to this bug, applied to OP's example, simply making the dependent type non-dependent, as the associated template parameter can be deduced from elsewhere (namely from the first template argument in OP's example). This would not work for the examples above, where we rely solely on the dependent type deduction in the deduction of the non-type template parameter to find the type of the type template parameter (which is the dependent type in the former).
For an actual client API, requiring the client to explicitly specify the type of the argument to the function which is provided as another argument, when the former is entirely deducible from the latter, is arguably redundant design, and opens up for client confusion when providing conflicting arguments for these two template parameters. Thus, we'd arguably like to fall back on the partial specialization technique shown above, but as shown in these answers, GCC fails us in this regard in case we'd like the client to not be restricted to a specific return type.
A workaround to mitigate the GCC bug
We can work our way around this, however, by using the same approach as above, still relying on [temp.deduct.type]/13, but by using an additional type template parameter (for the return type) in the partial specialization:
#include <iostream>
template <auto>
struct C { static void dispatch() = delete; };
template <typename T, typename Return, Return (*fun)(T)>
struct C<fun> {
static void dispatch() {
T t{};
fun(t);
}
};
void f(int) { std::cout << "void f(int)\n"; }
int g(int) { std::cout << "int f(int)\n"; return 0; }
int main() {
C<f>::dispatch();
C<g>::dispatch();
}
The client will not need to worry about the additional template parameters of the partial specialization, as they entirely deducible via the third non-type template parameter of the specialization, in whose declaration they are dependent. This final example is accepted by both GCC and Clang.
This is CWG2476: [dcl.spec.auto]/2 requires that auto used as (part of) a return type without a trailing-return-type appear only where the function declarator declares a function. The template parameter declaration doesn’t do that, so it’s invalid. One could argue that /5 allows it in a template parameter’s decl-specifier-seq regardless, but that doesn’t make sense because it would deprive the following of meaning:
template<auto g() -> int>
int f() {return g();}
That said, the deduction rules would work here, so this is a defect in the wording that will probably be fixed by saying that return type deduction just doesn’t happen in the cases where auto is allowed for other reasons.
As already stated by #songyuanyao this seems to be a gcc bug.
For <= c++17 One solution is to move type T form function signature to non-deduced context:
template <typename T>
struct identity { using type = T; };
and then
template <typename T, auto (*Func)(typename identity<T>::type)>
struct foo {
void bar(T t) { Func(t); }
};
Another approach is to change design and to move to a member function template. The auto type deduction works in this case:
void returnsVoid(int) { }
template <typename T>
struct foo {
template <auto (*Func)(T)>
void bar(T t) { Func(t); }
};
int main(int, char *[]) {
foo<int> a;
a.bar<returnsVoid>(3);
}
Live

Template type-deduction performs implicit array-to-pointer conversion

I've read existing questions about this standard conversion.
However, I didn't find a satisfying answer.
I have this piece of code which shows that the T* overload is chosen over the T&& one. From what I understood, the forwarding reference overload should bind everything, unless another overload is a perfect match.
In the following code, tab is a char const(&)[4].
Could someone explain to me why the array-to-pointer conversion is performed here?
And if there is a way to workaround that conversion, I'm all ears!
(coliru link)
#include <utility>
template <typename T>
void f(T&& lol)
{
}
template <typename T>
void f(T* pof)
{
static_assert(sizeof(T) && false, "");
}
template <typename T>
struct S;
int main(int argc, char *argv[])
{
decltype("lol") tab = "lol";
S<decltype(tab)> s;
f("lol");
return 0;
}
Arrays are deduced to Ptr types.
see http://en.cppreference.com/w/cpp/language/template_argument_deduction
Before deduction begins, the following adjustments to P and A are
made:
1) If P is not a reference type,
a) if A is an array type, A is replaced by the pointer type obtained from array-to-pointer conversion;
b) otherwise, if A is a function type, A is replaced by the pointer type obtained from function-to-pointer conversion;
c)otherwise, if A is a cv-qualified type, the top-level cv-qualifiers are ignored for deduction
A single-argument function template f is considered more specialized than a template g if an arbitrary type corresponding to the argument of f can be deduced to the argument of g, but not vice versa.
An arbitrary pointer type T* can be deduced to T&&, but this does not hold in the reverse direction (T&& cannot be deduced to T* in the general case), so f(T*) is considered more specialized than f(T&&).
To resolve this, we have to make f(T*) less attractive to the compiler, for example using SFINAE:
template <typename U,
typename T = std::enable_if_t<std::is_pointer<U>::value, std::remove_pointer_t<U>>>
void f(U const& pof) // U == T*

Type deduction fails with pointer to member method

I have the following template class which acts as a proxy. It has a method named call which is supposed to be used to call methods on the wrapped object. There's a problem with it. The type deduction fails and I cannot understand why.
Hudsucker::f takes an std::string and then no matter if I pass an std::string or a const reference to it the compiler is able to call the right method.
But in case of Hudsucker::g with takes a const reference to std::string type deduction fails in both cases with both GCC and Clang.
GCC error for the first line:
main.cpp:36:28: error: no matching function for call to ‘Proxy<Hudsucker>::call(void (Hudsucker::*)(const string&), const string&)’
main.cpp:36:28: note: candidate is:
main.cpp:10:10: note: template<class A> void Proxy::call(void (T::*)(A), A) [with A = A; T = Hudsucker]
main.cpp:10:10: note: template argument deduction/substitution failed:
main.cpp:36:28: note: deduced conflicting types for parameter ‘A’ (‘const std::basic_string<char>&’ and ‘std::basic_string<char>’)
Especially this bit is strange: no matching function for call to Proxy<Hudsucker>::call(void (Hudsucker::*)(const string&), const string&). That is exactly the signature I would expect to see work.
Clang error for the first line:
main.cpp:36:7: error: no matching member function for call to 'call'
p.call(&Hudsucker::g, s); // <- Compile error
~~^~~~
main.cpp:10:10: note: candidate template ignored: deduced conflicting types for parameter 'A' ('const std::basic_string<char> &' vs. 'std::basic_string<char>')
void call(void (T::*f)(A), A a)
Code:
#include <string>
#include <iostream>
template <typename T> class Proxy
{
public:
Proxy(T &o): o_(o) {}
template <typename A>
void call(void (T::*f)(A), A a)
{
(o_.*f)(a);
}
private:
T &o_;
};
class Hudsucker
{
public:
void f(std::string s) {}
void g(std::string const &s) {}
};
int main()
{
Hudsucker h;
Proxy<Hudsucker> p(h);
std::string const s = "For kids, you know.";
std::string const &r = s;
p.call(&Hudsucker::f, s);
p.call(&Hudsucker::f, r);
p.call(&Hudsucker::g, s); // <- Compile error
p.call(&Hudsucker::g, r); // <- Compile error
return 0;
}
Could you explain why the type deduction fails in that way? Is there a way to get this to compile with const references?
The compiler cannot deduce the type A, since it has contrasting information. From the type of the member function, it would deduce A to be std::string const&, while from the type of the second argument, it would deduce it to be std::string.
Change your function template into one that allows different types for the parameter of the member function and the argument actually provided, and then SFINAE-constrain the latter to be convertible to the former:
template <typename A, typename B,
typename std::enable_if<std::is_convertible<B, A>::value>::type* = nullptr>
void call(void (T::*f)(A), B a)
{
(o_.*f)(a);
}
If you are wondering why from this function call:
std::string const s = "For kids, you know.";
// ...
p.call(&Hudsucker::g, s);
The compiler would deduce std::string, that's because of paragraph 14.8.2.1/2 of the C++11 Standard:
If P is not a reference type:
— If A is an array type, the pointer type produced by the array-to-pointer standard conversion (4.2) is
used in place of A for type deduction; otherwise,
— If A is a function type, the pointer type produced by the function-to-pointer standard conversion (4.3)
is used in place of A for type deduction; otherwise,
— If A is a cv-qualified type, the top level cv-qualifiers of A’s type are ignored for type deduction.
In the quoted paragraph, P is your A (from your function template) and A is std::string const. This means the const in std::string const is ignored for type deduction. To see this better, consider this simpler example:
#include <type_traits>
template<typename T>
void foo(T t)
{
// Does NOT fire!
static_assert(std::is_same<T, int>::value, "!");
}
int main()
{
int const x = 42;
foo(x);
}
Considering the second function call:
std::string const &r = s;
// ...
p.call(&Hudsucker::g, r);
The reason is that the type of the id-expression r is std::string const. The reference is dropped because of paragraph 5/5:
If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to T prior to
any further analysis. The expression designates the object or function denoted by the reference, and the
expression is an lvalue or an xvalue, depending on the expression.
And now we're back to the same situation as for the first function call.
As pointed out by Mike Vine in the comments, you may want to perfectly-forward your second argument when giving it in input to the first (member function) argument during the function call:
#include <utility> // For std::forward<>()
template <typename A, typename B,
typename std::enable_if<std::is_convertible<B, A>::value>::type* = nullptr>
void call(void (T::*f)(A), B&& a)
{
(o_.*f)(std::forward<B>(a));
}
If you cannot afford C++11, then you won't be allowed to use default arguments for template parameters. In that case, you can use the SFINAE-constraint on the return type:
template <typename A, typename B>
typename enable_if<is_convertible<B, A>::value>::type
// ^^^^^^^^^ ^^^^^^^^^^^^^^
// But how about these traits?
call(void (T::*f)(A), B a)
{
(o_.*f)(a);
}
Notice, that std::enable_if and std::is_convertible are not part of the C++03 Standard Library. Fortunately, Boost has its own version of enable_if and is_convertible, so:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
template <typename T> class Proxy
{
public:
Proxy(T &o): o_(o) {}
template <typename A, typename B>
typename boost::enable_if<boost::is_convertible<B, A>>::type
call(void (T::*f)(A), B a)
{
(o_.*f)(a);
}
private:
T &o_;
};
Notice, that boost::enable_if accepts as its first template argument a type which defines a value boolean member, whereas std::enable_if accepts a boolean value. The equivalent of std::enable_if in Boost is boost::enable_if_c.
Seems to me a simpler solution would be to just exclude one of the two arguments from trying to deduce A, and the second one is the better candidate:
template <typename A>
void call(void (T::*f)(A), typename std::identity<A>::type a)
{
(o_.*f)(a);
}
If you don't have std::identity in your type traits, use this one:
template <typename T>
struct identity { typedef T type; };
Here's why this works: the compiler cannot deduce A from the second argument, since it's just a template parameter to something that a nested type is taken of. Basically, it can't pattern-match any incoming type against something_that_contains_A::type - due to template specialization, it can't reverse-engineer the argument from the definition of the left side. The net result is that the second argument is an "undeduced context". The compiler will not attempt to deduce A from there.
This leaves the first argument as the only place where A can be deduced from. With only one deduction result for A, it is not ambiguous and deduction succeeds. The compiler then proceeds to substitute the deduction result into every place where A was used, including the second argument.
You just need to pass template argument to template function when calling it in your main.
int main()
{
Hudsucker h;
Proxy<Hudsucker> p(h);
std::string const s = "For kids, you know.";
std::string const &r = s;
p.call(&Hudsucker::f, s);
p.call(&Hudsucker::f, r);
//just add template argument to template function call !!!
p.call< const std::string & > (&Hudsucker::g, s); // <- NO Compile error !!!!
p.call< const std::string & > (&Hudsucker::g, r); // <- NO Compile error !!!**
return 0;
}

In which cases one needs to specify the template's argument `types` specifically?

// Function declaration.
template <typename T1,
typename T2,
typename RT> RT max (T1 a, T2 b);
// Function call.
max <int,double,double> (4,4.2)
// Function call.
max <int> (4,4.2)
One case may be when you need to specify the return type.
Is there any other situation which requires the argument types to be specified manually?
(1) When there is no argument to the function and still it's a template type, then you may have to specify the arguments explicitly
template<typename T>
void foo ()
{}
Usage:
foo<int>();
foo<A>();
(2) You want to distinguish between value and reference.
template<typename T>
void foo(T obj)
{}
Usage:
int i = 2;
foo(i); // pass by value
foo<int&>(i); // pass by reference
(3) Need another type to be deduced instead of the natural type.
template<typename T>
void foo(T& obj)
{}
Usage:
foo<double>(d); // otherwise it would have been foo<int>
foo<Base&>(o); // otherwise it would have been foo<Derived&>
(4) Two different argument types are provided for a single template parameter
template<typename T>
void foo(T obj1, T obj2)
{}
Usage:
foo<double>(d,i); // Deduction finds both double and int for T
If the function template parameter appears in the function parameter list, then you don't need to specify the template parameters. For example,
template<typename T>
void f(const T &t) {}
Here T is a template parameter, and it appears in the function parameter list, i.e const T &t. So you don't need to specify the template parameter when calling this function:
f(10); //ok
Since the type of 10 is int, so the compiler can deduce the template parameter T from it, and T becomes int.
Note that since the type deduction is done from using the information of the function arguments, its called template argument deduction. Now read on.
If the template parameter doesn't appear in the function parameter list, then you have to provide the template parameter. Example:
template<typename T>
void g(const int &i) {}
Notice g() is different from f(). Now T doesn't appear in the function parameter list. So:
g(10); //error
g<double>(10); //ok
Note that if a function template templatizes on the return type as well, and the return type is different from the types appearing the function parameter list, then you've to provide the return type:
template<typename T>
T h(const T &t) {}
Since return type T is same as the function parameter, type deduction is possible from function argument:
h(10); //ok - too obvious now
But if you've this:
template<typename R, typename T>
R m(const T &t) {}
Then,
m(10); //error - only T can be deduced, not R
m<int>(10); //ok
Note that even though the function template m has templatized on two types : R and T, we've provided only ONE type when calling it. That is, we've written m<int>(10) as opposed to m<int,int>(10). There is no harm in writing the later, but its okay, if you don't. But sometimes you've to specif both, even if one type T can be deduced. It is when the order of type parameters is different as shown below:
template<typename T, typename R> //note the order : its swapped now!
R n(const T &t) {}
Now, you've to provide both types:
n(10); //error - R cannot be deduced!
n<int>(10); //error - R still cannot be deduced, since its the second argument!
n<int,int>(10); //ok
The new thing here is : the order of type parameters is also important.
Anyway, this covers only the elementary concept. Now I would suggest you to read some good book on templates, to learn all the advanced things regarding type deduction.
In general, you need to explicitly specify the types when the compiler can't figure it out on its own. As you mentioned, this often happens when the return type is templatized, since the return type cannot be inferred from the function call.
Template classes have the same problem -- instantiating a std::vector offers no way for the compiler to determine what type your vector is storing, so you need to specify std::vector<int> and so forth.
The type resolution is only performed in the case of function arguments, so it may be easier to view that as the special case; ordinarily, the compiler is unable to guess what type(s) to use.
The simple answer is that you need to provide the types when the compiler cannot deduce the types by itself, or when you want the template to be instantiated with a particular type that is different from what the compiler will deduce.
There are different circumstances when the compiler cannot deduce a type. Because type deduction is only applied to the arguments (as is the case with overload resolution) if the return type does not appear as an argument that is deducible, then you will have to specify it. But there are other circumstances when type deduction will not work:
template <typename R> R f(); // Return type is never deduced by itself
template <typename T>
T min( T const & lhs, T const & rhs );
min( 1, 2 ); // Return type is deducible from arguments
min( 1.0, 2 ); // T is not deducible (no perfect match)
min<double>( 1.0, 2 ); // Now it is ok: forced to be double
min<double>( 1, 2 ); // Compiler will deduce int, but we want double
template <typename T>
void print_ptr( T* p );
print_ptr<void>( 0 ); // 0 is a valid T* for any T, select manually one
template <typename T>
T min( T lhs, T rhs );
int a = 5, b = 7;
min<int&>(a,b)++; // Type deduction will drop & by default and call
// min<int>(a,b), force the type to be a reference
template <typename C>
typename C::value_type
min_value( typename C::const_iterator begin, typename C::const_iterator end );
std::vector<int> v;
min_value<std::vector<int> >( v.begin(), v.end() );
// Argument type is not deducible, there are
// potentially infinite C that match the constraints
// and the compiler would be forced to instantiate
// all
There are probably more reasons for an argument type cannot be deduced, you can take a look at §14.8.2.1 in the standard for the specifics of deduction of arguments from a function call.