Playing yet again with variadic templates:
template <typename... Ts1>
constexpr bool ends_with_int(Ts1... ts1) {
return false;
}
template <typename... Ts1>
constexpr bool ends_with_int(Ts1... ts1, int i) {
return true;
}
int main() {
std::cout << std::boolalpha;
std::cout << ends_with_int(1, 2, 3) << std::endl;
std::cout << ends_with_int<int, int, int>(1, 2, 3) << std::endl;
std::cout << ends_with_int(3) << std::endl;
// below is very similar to the spec example at 14.8.2.1/1
std::cout << ends_with_int<int, int>(1, 2, 3) << std::endl;
}
Code: http://coliru.stacked-crooked.com/a/f0efb99a0c8f690a
Output
|---|---------------------------------------------------------------|
| # | ends_with_int | clang (3.8) | g++ (6.1) |
|---|-----------------------------------|-------------|-------------|
| 1 |1, 2, 3 | false | false |
|---|---------------------------------------------------------------|
| 2 |<int, int, int>(1, 2, 3) | false | false |
|---|---------------------------------------------------------------|
| 3 | 3 | true | ambiguity |
|---|---------------------------------------------------------------|
| 4 |<int, int>(1, 2, 3) | true | ambiguity |
|---|---------------------------------------------------------------|
Case 4 is very similar to the example at 14.8.2.1/1 in the spec:
template<class T1, class ... Types> void g1(Types ..., T1);
void h(int x, float& y) {
const int z = x;
g1(x, y, z); // error: Types is not deduced
g1<int, int, int>(x, y, z); // OK, no deduction occurs
}
IMHO, gcc behavior for case 4 is surprising, clang seems to capture that better. For case 3 it is not clear to me who is right.
But the difference between the compilers seem to signal that the spec wording for variadic templates is either too complicated or not closing all corners, specifically for the case where function parameter pack is not the last. (See also other variadic template different behavior between clang and gcc).
Trying to understand from the spec what is the correct behavior, it seems that the answer is somewhere in the rules of 14.1/11, 14.8.2.1/1 and 14.8.2.5/9, but these sections may contradict each other, to my layman eyes, or at least I need a spec lawyer to assist.
From 14.1/11:
... A template parameter pack of a function template shall not be followed by another template parameter unless that template parameter can be deduced from the parameter-type-list of the function template [...]
From 14.8.2.1/1:
... Each deduction deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack. When a function parameter pack appears in a non-deduced context ([temp.deduct.type]), the type of that parameter pack is never deduced. [...]
From 14.8.2.5/9:
... If the template argument list of P contains a pack expansion that is not the last template argument, the entire template argument list is a non-deduced context. [...]
Do you see a problem with the wording in the spec? Or is it clear what is the right behavior and compilers shall just align?