Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why template with only valid empty variadic pack ill formed?

What is the rationale of

temp.res#8.3

(8) The validity of a template may be checked prior to any instantiation. [ Note: Knowing which names are type names allows the syntax of every template to be checked in this way. — end note ] The program is ill-formed, no diagnostic required, if:
[..]
(8.3) every valid specialization of a variadic template requires an empty template parameter pack, or

That rule disallows trick as following to force template deduction as:

template <typename ...Ts,
          typename A,
          typename B,
          std::enable_if_t<sizeof...(Ts) == 0, int> = 0> // Ill-formed NDR :-(
Pair<std::decay_t<A>, std::decay_t<B>> MakePair(A&&a, B&& b)
{
    return {a, b};
}

Note: I know that C++17 deduction rule makes make_* obsolete.

like image 459
Jarod42 Avatar asked Nov 29 '18 18:11

Jarod42


People also ask

What is the use of Variadic templates?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.

What is parameter pack in c++?

Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.

What is Pack expansion?

Pack expansion A pattern followed by an ellipsis, in which the name of at least one parameter pack appears at least once, is expanded into zero or more comma-separated instantiations of the pattern, where the name of the parameter pack is replaced by each of the elements from the pack, in order. template<class...


Video Answer


1 Answers

In general, implementations can diagnose obvious errors in templates early, since you can't generate a valid instantiation anyway. But pack expansion is a bit unique because the whole construct can just disappear when instantiated. The rule therefore is needed to disallow various species of obvious bogosity in things being pack-expanded and permit their early diagnosis:

template<class...Ts>
union U : Ts... {}; // unions can't have base classes

template<class...Ts>
class C : Ts..., Ts... {}; // classes can't have duplicate direct base classes

template<class...Ts>
void f() {
    // sizeof(void) is invalid, but it can vanish
    int x[] = {(sizeof(void) + sizeof(Ts))..., 0};
}

This also somewhat helps compiler implementers, because their internal representation for templates need not support such nonsense.

like image 190
T.C. Avatar answered Sep 30 '22 03:09

T.C.