tags:

views:

355

answers:

3

Hello, I created two simple functions which get template parameters and an empty struct defining a type:

//S<T>::type results in T&
template <class T>
struct S
{
    typedef typename T& type;
};

//Example 1: get one parameter by reference and return it by value
template <class A>
A
temp(typename S<A>::type a1)
{
    return a1;
}

//Example 2: get two parameters by reference, perform the sum and return it
template <class A, class B>
B
temp2(typename S<A>::type a1, B a2)//typename struct S<B>::type a2)
{
    return a1 + a2;
}

The argument type is applied to the struct S to get the reference. I call them with some integer values but the compiler is unable to deduce the arguments:

int main()
{
    char c=6;
    int d=7;
    int res = temp(c);
    int res2 = temp2(d,7);
}

Error 1 error C2783: 'A temp(S::type)' : could not deduce template argument for 'A'

Error 2 error C2783: 'B temp2(S::type,B)' : could not deduce template argument for 'A'


Why is this happening? Is it that hard to see that the template arguments are char and int values?

Thanks!

+9  A: 
ltcmelo
welcome to SO. and +1 :)
Johannes Schaub - litb
I edited the quote for some time. You first, so +1 :)
Kirill V. Lyadvinsky
+3  A: 

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>, both T and T2 are nondeduced. Likewise, if a type is specified as A<I+J>::X<T>, I, J, and T are nondeduced. If a type is specified as void f(typename A<T>::B, A<T>), the T in A<T>::B is nondeduced but the T in A<T> is deduced. ]

Kirill V. Lyadvinsky
+2  A: 

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>::vaue);
    typedef typename SA::type A;

    ...
}

Using your favorite static assert library (Boost has two).

Marsh Ray