12
votes

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
Aliases are just aliases. It's like writing template <typename T> void f(typename A<T>::type);, which isn't deducible. - Kerrek SB
I'd think Kerrek SB is correct about this. If had provided a quote I wouldn't need to go off and search one ;-) - Dietmar Kühl
@Nawaz: I don't think it is a duplicate: this is about template aliases and I can't see any hint of template aliases in the question you pointed to. - Dietmar Kühl
@Nawaz: please actually read the question before marking it a duplicate... - HighCommander4

3 Answers

2
votes

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.

10
votes

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.

1
votes

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.