Неоднозначное разрешение перегрузки С++ - GCC

Я пытаюсь понять, почему GCC выбирает f(char, A<C, 5> &var) для разрешения перегрузки в коде ниже:

template <class C, int N> struct A { };
template <class C> struct A<C, 8> { static_assert(sizeof(C) > 8, "Assertion in A<C,8>"); };
template <class C> struct A<C, 5> { static_assert(sizeof(C) < 8, "Assertion in A<C,5>"); operator A<C,8>&(); };

template <class C> void f(double, A<C,8> &var);
template <class C> void f(char, A<C,5> &var);

int main(void)
{
    A<int, 5> a;
    f(4., a);
}

Доступны две перегрузки:

template <class C> void f(double, A<C,8> &var);

4. точно соответствует double (неявное преобразование не требуется), но для второго параметра требуется пользовательское преобразование. Итак, эта перегрузка: exact match и user-define conversion

Следующая перегрузка, которая соответствует GCC:

template <class C> void f(char, A<C,5> &var);

4. требует неявного преобразования в char, но точного соответствия для A<C,5>. Есть ли причина, по которой GCC выбирает эту перегрузку по сравнению с предыдущей?

Может ли кто-нибудь найти доказательства из раздела 13 стандарта по этому конкретному делу? Любая помощь или комментарий приветствуются. Спасибо!


person Shivam    schedule 21.01.2014    source источник


Ответы (1)


Дедукция не может быть успешной для

template <class C> void f(double, A<C,8> &var);

и аргумент типа A<int, 5>. т.е. нет возможного типа C, который мог бы заставить A<C,8> соответствовать типу аргумента A<int,5>. То, что преобразование возможно, не заботится о дедукции.

См. [temp.deduct.call]/4. Поскольку преобразования могут быть разрешены с помощью конструкторов преобразования, а также функций преобразования, невозможно учитывать (все) преобразования для вывода типа. Это также может привести к двусмысленности.

person dyp    schedule 21.01.2014
comment
Вы можете увидеть это, удалив вторую перегрузку. Вывод clang++: шаблон-кандидат проигнорирован: не удалось сопоставить 8 против 5 - person dyp; 21.01.2014
comment
вы правы, gcc тоже выдает ошибки, когда закомментирована вторая перегрузка. - person Maxim Egorushkin; 21.01.2014
comment
Спасибо за ответ. Таким образом, clang и gcc не заботятся о пользовательском преобразовании. Это operator A<C,8>&();? - person Shivam; 21.01.2014
comment
@User Вывод типа Well не учитывает возможные преобразования, operator A<C,8>& () - это одно из таких преобразований, которое не учитывается для вывода типа. Если вы явно передаете аргументы шаблона (как правило, это не рекомендуется), вы получите ожидаемую неоднозначность: f<int>(4., a); неоднозначно - person dyp; 21.01.2014