I'm struggling to understand how deduction works in the following case:
template<class Category, Category code>
struct AImpl
{ };
template<class Category, Category code>
struct AHelper
{
using type = AImpl<Category, code>;
};
template<class Category, Category code>
using A = typename AHelper<Category, code>::type;
template<int code>
void doSomething(A<int, code> object)
{
}
Following is the test code:
A<int, 5> a1;
doSomething(a1); // This does not compile
doSomething<5>(a1); // This compiles
Why a1 is not deduced in this context?
If you modify A in the following way instead:
template<class Category, Category code>
struct A
{ };
Both work. Anyone knows why?
[edit] question linked to Mixing aliases and template specializations
Because the template argument of
doSomething
appears in a non-deduced context. An alias template stands almost exactly for what it aliases. And yours is defined as follows:To deduce
code
, the compiler will need to deduce something on the left of::
and that is a non-deduced context. Template argument deduction won't even attempt to deduce something if it appears as an argument to the left of the scope resolution operator.It's not without cause that this is an undeduced context. Remember that templates may be specialized. I could add this:
A compiler will need to look at all the code in the entire program and try all the types to be sure nothing nefarious is happening for it to be certain that
a1
really matches astypename AHelper<Category, code>::type
. That's intractable. So a mapping by meta-functions is a one way street only. You can't ask the compiler to deduce the source type (or non-type argument) from the target type.