How do template aliases affect template parameter deduction?
Asked Answered
M

3

13

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?

Myoglobin answered 8/1, 2012 at 3:39 Comment(6)
Aliases are just aliases. It's like writing template <typename T> void f(typename A<T>::type);, which isn't deducible.Katheryn
possible duplicate of C++, template argument can not be deducedHeterodox
I'd think Kerrek SB is correct about this. If had provided a quote I wouldn't need to go off and search one ;-)Eugenaeugene
@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.Eugenaeugene
@Nawaz: please actually read the question before marking it a duplicate...Myoglobin
Oops. I misread the question.Heterodox
T
11

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.

Thorncombe answered 8/1, 2012 at 10:49 Comment(1)
The key phrase in Johannes' excellent answer is “At the definition time of f already” (emphasis mine). It's easy to miss that, but knowing it explains everything.Refill
K
2

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.

Katheryn answered 8/1, 2012 at 3:48 Comment(0)
A
1

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.

Ascensive answered 8/1, 2012 at 4:4 Comment(3)
Your last statement is incorrect. What your quote regarding deduction says is that the alias template name cannot be deduced. That is template<template<typename T> class C> void f(C<T>); ref<int> r; f(r); is not possible to deduce C == ref (given my definition of ref in my answer). It does not mean what you conclude it means.Thorncombe
OK, I can accept this. However, yesterday I haven't found a better quotes (but I may have been confuddled). Can you point me towards a quote in the standard?Eugenaeugene
you quoted it yourself. The template-id ref<T> is equivalent to T& by the quote you have given. And hence the non-normative note says that it is unusable to deduce ref. But it is usable for deducing T, because of this early-replacement. See the solution of open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#395 and https://mcmap.net/q/368541/-alias-template-specialisationThorncombe

© 2022 - 2024 — McMap. All rights reserved.