Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understand how to compute sum at compile time

I have this piece of code and want to understand:

template <unsigned...>
struct sum;

template<unsigned size>
struct sum<size>
{
    enum {value = size};
};

template<unsigned size, unsigned... sizes>
struct sum<size, sizes...>
{
    enum { value = size + sum<sizes...>::value }; 
};

int _tmain(int argc, _TCHAR* argv[])
{
    sum<1, 2>::value;
    return 0;
}

I don't understand why the unimplemented sum(that takes unsigned... just as last struct specialization, isn't there a conflict?) must be present at all and how one can specialize sum using same parameters from template part (e.g. sum<size, sizes...> same as template <unsigned size, sizes...>. Why the bellow just doesn't work ?

template<unsigned size>
struct sum
{
    enum {value = size};
};

template<unsigned size, unsigned... sizes>
struct sum
{
    enum { value = size + sum<sizes...>::value; }; 
};
like image 590
Gmt Avatar asked Feb 16 '23 08:02

Gmt


1 Answers

Notice that the syntax is a bit different. When you declare the primary template:

template <unsigned...>
struct sum;

You don't give the template parameters after sum. This is because you are creating a brand new template, and saying that it takes an arbitrary number of unsigned integers as parameters.

When you are doing this:

template<unsigned size, unsigned... sizes>
struct sum<size, sizes...>
{
    enum { value = size + sum<sizes...>::value }; 
};

you are specializing the template that you declared before. You are saying that in the case where your parameters consist of an unsigned value followed by an arbitrary number of other unsigned values, use this definition. This isn't exactly the same as the primary template. The primary template includes the possibility of having zero parameters.

When you try to do this:

template<unsigned size>
struct sum
{
    enum { value = size };
};

template<unsigned size, unsigned... sizes>
struct sum // OOPS! A template called `sum` has already been declared!
{
    enum { value = size + sum<sizes...>::value }; 
};

you are trying to make two different class templates with the same name, which isn't allowed.

Note that this is a bit different from how function templates work. With function templates, you can do overloading, so having multiple function templates with the same name is fine. However with function templates, you can't do partial specialization, since this would create a lot of ambiguity.

You might think that there is ambiguity between the primary template and the specializations, but more-specialized specializations always take precedence over less-specialized specializations, and the primary template can always be considered the least specialized. If this wasn't true, then partial specialization wouldn't work at all.

like image 146
Vaughn Cato Avatar answered Feb 17 '23 20:02

Vaughn Cato