Why is an ellipsis preferred to a variadic template when called with no arguments?

c++, c++11, sfinae, templates, variadic-templates

Solution

When `T...` is empty, the compiler performs overload resolution to determine which of

std::true_type check(); // instantiated from the function template
std::false_type check(...);

is the best viable candidate, as described in [over.match.best] 13.3.3/1 (quoting N3936):

Define ICSi(F) as follows:

if F is a static member function, ICS1 (F) is defined such that ICS1 (F) is neither better nor worse than ICS1 (G) for any function G, and, symmetrically, ICS1 (G) is neither better nor worse than ICS1 (F)132; otherwise,

let ICSi(F) denote the implicit conversion sequence that converts the i-th argument in the list to the type of the i-th parameter of viable function F. 13.3.3.1 defines the implicit conversion sequences and 13.3.3.2 defines what it means for one implicit conversion sequence to be a better conversion sequence or worse conversion sequence than another.

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then

for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,

the context is an initialization by user-defined conversion (see 8.5, 13.3.1.5, and 13.3.1.6) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type. [ Example:

struct A {
  A();
  operator int();
  operator double();
} a;
int i = a; // a.operator int() followed by no conversion
// is better than a.operator double() followed by
// a conversion to int
float x = a; // ambiguous: both possibilities require conversions,
// and neither is better than the other

—end example ] or, if not that,

the context is an initialization by conversion function for direct reference binding (13.3.1.6) of a reference to function type, the return type of F1 is the same kind of reference (i.e. lvalue or rvalue) as the reference being initialized, and the return type of F2 is not [ Example:

template <class T> struct A {
  operator T&(); // #1
  operator T&&(); // #2
};
typedef int Fn();
A<Fn> a;
Fn& lf = a; // calls #1
Fn&& rf = a; // calls #2

—end example ] or, if not that,

F1 is not a function template specialization and F2 is a function template specialization, or, if not that,

- F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.6.2.

In this case, the conversion sequences for both candidates are empty since there are no arguments. The second to last bullet is the deciding factor:

- F1 is not a function template specialization and F2 is a function template specialization, or, if not that,

hence the non-template `std::false_type check(...);` is preferred.

My preferred workaround - obviously there are many - would be to make both candidates templates and discriminate via the ellipsis conversion [over.ics.ellipsis] 13.3.3.1.3/1:

An ellipsis conversion sequence occurs when an argument in a function call is matched with the ellipsis parameter specification of the function called (see 5.2.2).

by giving the "preferred" template declaration an extraneous parameter that is a clearly better match, since any other conversion sequence will be preferred to an ellipsis conversion per [over.ics.rank] 13.3.3.2/2:

When comparing the basic forms of implicit conversion sequences (as defined in 13.3.3.1)

- a standard conversion sequence (13.3.3.1.1) is a better conversion sequence than a user-defined conversion sequence or an ellipsis conversion sequence, and

- a user-defined conversion sequence (13.3.3.1.2) is a better conversion sequence than an ellipsis conversion sequence (13.3.3.1.3).

Example:

template<typename... T,
    typename = decltype(f(std::declval<T>()...))>
std::true_type check(int);
template<typename...>
std::false_type check(...);

template<typename... T> using Predicate = decltype(check<T...>(0));

Problem

I'm using the following SFINAE pattern to evaluate a predicate on a variadic type list: ``` #include <type_traits> void f(int = 0); // for example template<typename... T, typename = decltype(f(std::declval<T>()...))> std::true_type check(T &&...); std::false_type check(...); template<typename... T> using Predicate = decltype(check(std::declval<T>()...)); static_assert(!Predicate<int, int>::value, "!!"); static_assert( Predicate<int>::value, "!!"); static_assert( Predicate<>::value, "!!"); // fails int main() { } ``` To my surprise, the ellipsis overload is selected when `check` is called with an empty argument list, so `Predicate<>` is `std::false_type` even when the SFINAE-expression is valid! Shouldn't variadic function templates always be preferred to ellipsis functions? Are there any workarounds?

Original source