#include <iostream>
#include <cstdint>
template<int T> void foo()
{
std::cout << "a" << std::endl;
}
template<uint8_t T> void foo()
{
std::cout << "b" << std::endl;
}
int main()
{
foo<static_cast<uint8_t>(42)> ();
foo<static_cast<int>(42)>();
return(0);
}
Любая идея, почему это не работает, как ожидалось?
Мой gcc 4.8.1 жалуется на неоднозначный вызов, но static_cast не должен «исправлять» правило приоритета в случаях, подобных этому, когда у вас есть 2 типа с одинаковым приоритетом?
Можно подумать, что компилятор при разрешении перегруженных шаблонов функций пытается выяснить, какой из шаблонов лучше соответствует заданным аргументам. Исходя из этого предположения, шаблон с uint8_t
должен соответствовать вызов функции с uint8_t
аргумент лучше чем шаблон для int
,
Но это не то, как работает разрешение перегрузки шаблона. Разрешение перегрузки шаблона (§14.5.6.2) отличается от разрешения перегрузки обычной функции (§13.3). Сначала он устанавливает шаблоны-кандидаты, а затем, вместо того, чтобы пытаться проверить, насколько хорошо каждый из них соответствует заданным аргументам, он просто устанавливает, какой из двух (или более) шаблонов-кандидатов является наиболее специализированным.
Обратите внимание, что это вопрос только между шаблонами кандидатов. Он не учитывает заданные аргументы вызова функции. (Они принимаются во внимание для вывода типа, который является только частью процедуры, которая устанавливает набор шаблонов кандидатов.)
Так что он проверяет, uint8_t
более специализированный, чем int
или наоборот (в общем случае — не по отношению к заданным аргументам вызова функции под рукой). Он делает это, в основном, проверяя, есть ли uint8_t
аргумент (в теории) может быть использован для заполнения int
параметр без нестандартных преобразований и наоборот. Это так (в обоих направлениях), поэтому ни один шаблон не является более специализированным, чем другой. Следовательно, двусмысленность не может быть решена.
Соответствующие разделы стандарта следующие.
Во-первых, §13.3.3 устанавливает, что когда два шаблона функций (в отличие от двух обычных функций или одной функции и одного шаблона) конкурируют за вызов функции, механизм перегрузки шаблона используется для выбора наилучшего:
[…] жизнеспособная функция F1 определяется как лучшая функция, чем другая жизнеспособная функция
F2, если для всех аргументов i ICSi (F1) не хуже последовательности преобразования, чем ICSi (F2), а затем […] — F1 и F2 являются специализациями шаблонов функций, а шаблон функций для F1 более специализирован, чем шаблон для F2, согласно правилам частичного упорядочения, описанным в 14.5.6.2.
Тогда §14.5.6.2 очень длинный, но наиболее важными частями являются:
(2) Частичное упорядочение выбирает, какой из двух шаблонов функций является более специализированным, чем другой, путем преобразования каждого шаблона по очереди (см. Следующий абзац) и выполнения вывода аргумента шаблона с использованием типа функции. Процесс вывода определяет, является ли один из шаблонов более специализированным, чем другой. Если это так, то более специализированный шаблон выбирается в процессе частичного заказа.
(3) Чтобы создать преобразованный шаблон, для каждого типа, не типового или шаблонного параметра шаблона (включая его пакеты параметров шаблона (14.5.3)) синтезируйте уникальный тип, значение или шаблон класса соответственно и подставьте его для каждого вхождения этого параметра в типе функции шаблона. […]
(4) Используя тип функции преобразованного шаблона функции, выведите тип из другого шаблона, как описано в 14.8.2.4.
Идея здесь такова: возьмите uint8_t
шаблон и преобразование это путем замены uint8_t
параметр с фактическим синтезированным значением (я полагаю, что это значение может быть взято из фактического вызова функции, но стандарт этого не говорит). Затем используйте процесс вывода типа, чтобы проверить, будет ли преобразованный шаблон, взятый как вызов функции, «соответствовать» Другой шаблон (то есть int
шаблон), т.е. если int
Параметр другого шаблона мог быть выведен без нестандартных преобразований. Ответ — да, это возможно.
Тогда идите другим путем, возьмите int
шаблон, синтезировать значение и попробуйте, если это «соответствует» uint8_t
шаблон, т.е. если uint8_t
параметр может быть выведен без нестандартных преобразований. Ответ снова да.
Если это работает только в одном направлении, один из двух шаблонов должен быть более специализированным, чем другой, и выбран для устранения неоднозначности. Если это работает в обоих направлениях (как в вашем случае), неоднозначность не может быть решена.
Заметка. Вся процедура на самом деле более сложная, и ее описание в Стандарте очень длинное, в основном по следующим причинам:
Других решений пока нет …