Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template specialization and alias template deduction difference

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

like image 201
Saturnu Avatar asked May 03 '19 10:05

Saturnu


People also ask

What is meant by template specialization?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

What is template argument deduction in C++?

Class Template Argument Deduction (CTAD) is a C++17 Core Language feature that reduces code verbosity. C++17's Standard Library also supports CTAD, so after upgrading your toolset, you can take advantage of this new feature when using STL types like std::pair and std::vector.

What is alias declaration in C++?

You can use an alias declaration to declare a name to use as a synonym for a previously declared type. (This mechanism is also referred to informally as a type alias). You can also use this mechanism to create an alias template, which can be useful for custom allocators.

What is a deduction guide?

Template deduction guides are patterns associated with a template class that tell the compiler how to translate a set of constructor arguments (and their types) into template parameters for the class. The simplest example is that of std::vector and its constructor that takes an iterator pair.


1 Answers

Why a1 is not deduced in this context?

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:

template<class Category, Category code>
using A = typename AHelper<Category, code>::type;

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:

template<Category code>
struct AHelper<int, code>
{
    using type = BImpl<code>; // My own class!
};

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 as typename 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.

like image 96
StoryTeller - Unslander Monica Avatar answered Oct 12 '22 23:10

StoryTeller - Unslander Monica