Не является `void f (A <0>, tuple <T *...>)` более специализированным, чем `void f (A <I>, tuple <T *...>)`?

#include <tuple>

template<int I>
struct A {};

template<int I, typename... T>
void f(A<I>, std::tuple<T *...>) {}

template<typename... T>
void f(A<0>, std::tuple<T *...>) {}

int main()
{
    f(A<0>{}, std::tuple<char*, int*, float*>{});
}

Не вторая ли перегрузка f более специализированная? g++ 4.9.2 говорит, что вызов неоднозначен, clang 3.6.0 принимает его. Какой компилятор прав?

Интересно, что если вы меняете std::tuple<T *...> на std::tuple<T...>, g++ отлично справляется с этим, чего я не понимаю.

Ответы

Ответ 1

В соответствии с действующими правилами вторая перегрузка является более специализированной. Некоторая специализация A<@> с синтезированным значением @ не может быть сопоставлена ​​с A<0>, но A<0> может быть сопоставлена ​​с A<I>I=0). Эта первая асимметрия пары является решающей. Используете ли вы T или T*, поскольку шаблон во втором параметре не имеет значения, так как вычет преуспевает в обоих направлениях для этой пары.

Ошибка все еще сохраняется в багажнике и сообщается @Barry как 67228.