How do template aliases affect template parameter deduction?

1.5k views Asked by At

In C++03, template parameter deduction does not occur in some contexts. For example:

template <typename T> struct B {};

template <typename T>
struct A
{
    typedef B<T> type;
};

template <typename T>
void f(typename A<T>::type);

int main()
{
    B<int> b;
    f(b);  // ERROR: no match
}

Here, int is not deduced for T, because a nested type such as A<T>::type is a non-deduced context.

Had I written the function like this:

template <typename T> struct B {};

template <typename T>
void f(B<T>);

int main()
{
    B<int> b;
    f(b);
}

everything is fine because B<T> is a deduced context.

In C++11, however, template aliases can be used to disguise a nested type in syntax similar to the second example. For example:

template <typename T> struct B {};

template <typename T>
struct A
{
    typedef B<T> type;
};

template <typename T>
using C = typename A<T>::type;

template <typename T>
void f(C<T>);

int main()
{
    B<int> b;
    f(b);
}

Would template argument deduction work in this case? In other words, are template aliases a deduced context or a non-deduced context? Or do they inherit the deduced/non-deduced status of whatever they alias?

3

There are 3 answers

1
Johannes Schaub - litb On BEST ANSWER

In other words, are template aliases a deduced context or a non-deduced context?

They are as deducible as the equivalent code without using template aliases. For example

template<typename T>
using ref = T&;

template<typename T>
void f(ref<T> r);

Now you can call f(x) and T will be deduced perfectly fine. At the definition time of f already, ref<T> is replaced by type T&. And T& is a deduced context.

In your case C<T> is replaced by typename A<T>::type, and that is a non-deduced context for T, so T cannot be deduced.

0
Kerrek SB On

Imagine this:

template <typename T> struct Foo { typedef   T type; }
template <> struct Foo<char>     { typedef int type; }

template <typename T> using mytype = typename Foo<T>::type;

template <typename T> void f(mytype<T>);

Now if I want int n; f(n);, how could I decide whether I want T = int or T = char? The whole problem, which is unaffected by template aliases, is that you cannot deduce backwards to all the things that could possibly define something.

3
Dietmar Kühl On

I think the relevant quote in the C++ standard is 14.5.7 [temp.alias] paragraph 2:

When a template-id refers to the specialization of an alias template, it is equivalent to the associated type obtained by substitution of its template-arguments for the template-parameters in the type-id of the alias template. [ Note: An alias template name is never deduced. — end note ]

There is an example following the quote which effectively spells out that it is pointless to use an alias template in a function template and hoping to deduce the template argument. This apparently applies even for situation which don't involve nested types.