Why is the template argument deduction not working here?
Solution 1:
Just as first note, typename name is used when you mention a dependent name. So you don't need it here.
template <class T>
struct S
{
typedef T& type;
};
Regarding the template instantiation, the problem is that typename S<A>::type
characterizes a nondeduced context for A. When a template parameter is used only in a nondeduced context (the case for A in your functions) it's not taken into consideration for template argument deduction. The details are at section 14.8.2.4 of the C++ Standard (2003).
To make your call work, you need to explicitly specify the type:
temp<char>(c);
Solution 2:
It is looks like nondeduced context. According to C++ Standard 14.8.2.4/4:
The nondeduced contexts are:
- The nested-name-specifier of a type that was specified using a qualified-id.
- A type that is a template-id in which one or more of the template-arguments is an expression that references a template-parameter.
When a type name is specified in a way that includes a nondeduced context, all of the types that comprise that type name are also nondeduced. However, a compound type can include both deduced and nondeduced types. [Example: If a type is specified as
A<T>::B<T2>
, bothT
andT2
are nondeduced. Likewise, if a type is specified asA<I+J>::X<T>
,I
,J
, andT
are nondeduced. If a type is specified asvoid f(typename A<T>::B, A<T>)
, theT
inA<T>::B
is nondeduced but theT
inA<T>
is deduced. ]
Solution 3:
Deduction works in the forward direction:
template <class T> void f(T);
f(2); // can deduce int from T
Why is this happening?
It doesn't work in the backwards direction (your example):
template <class A> void g(typename S<A>::type);
Is it that hard to see that the template arguments are char and int values?
Template deduction can do some magical (Turing-complete) things, but I don't think this is one of them.
You might use something like (untested):
template <class SA> void h(SA a1)
{
STATIC_ASSERT(same_type<SA, S<A>::type>::value);
typedef typename SA::type A;
...
}
Using your favorite static assert library (Boost has two).