2013-06-26 4 views
9
#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); 
} 

любая идея, почему это не работает должным образом?static_cast не работает по приоритету, как ожидалось

Мой gcc 4.8.1 жалуется на неоднозначный вызов, но static_cast не должен «исправлять» правило приоритета в случаях, подобных этому, где у вас есть 2 типа с одинаковым приоритетом?

+0

Я хочу сказать, что это не работает, потому что 'uint8_t' на самом деле является typedef из' int' (что делает его по существу тем же самым типом) в этом случае, тогда как static_cast обычно используется для разрешения правил приоритета, касающихся неявных приведения типов и т.п. Хотя это может быть неправильно. –

+0

@SilvioMayolo не стесняйтесь попробовать с другими типами с тем же приоритетом int, он все еще не работает для меня ... – user2485710

+0

Прошу прощения за мое полное незнание: может кто-нибудь перенаправить меня в какую-то документацию о том, что здесь происходит? Как называется этот новый тип шаблонов? Для чего они служат? – Antonio

ответ

5

Вы могли бы подумать, что компилятор при разрешении перегруженных шаблонов функций пытается выяснить, какой из шаблонов лучше соответствует данным аргументам. Исходя из этого предположения, шаблон с 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 можно вывести без нестандартных преобразований. Ответ - да.

Если это работает только в одном направлении, один из двух шаблонов должен быть более специализированным, чем другой, и выбран для устранения двусмысленности. Если он работает в обоих направлениях (как в вашем случае), двусмысленность не может быть решена.

Примечание. Вся процедура на самом деле более сложным, и его описание в стандарте очень долго, в основном по следующим причинам:

  • Сам процесс дедукции типа является сложным. Он допускает определенные неявные преобразования (в основном, стандартные преобразования, в том числе связанные с cv-квалификаторами);
  • Он имеет ряд специальных правил арбитража для случая, когда один параметр-кандидата является константой-ссылкой, а другой - в неконстантной ссылке и в некоторых подобных случаях;
  • Каждый шаблон-кандидат может приводить к появлению нескольких преобразованных шаблонов, особенно при выборе более одного параметра шаблона;
  • Наличие аргументов по умолчанию, а также пакетов параметров шаблонов усложняет ситуацию.
+0

@OP Обратите внимание, что у нас был аналогичный вопрос вчера: http://stackoverflow.com/questions/17313649/how-can-i-distinguish-overloads-of-templates-with-non-type-parameters/17313930#comment25112617_17313930 Я все еще размышляю о том, ваши ли вы (спрашиваете «почему»,) следует рассматривать как дубликат вчерашнего дня (вопрос «как разрешить»). – jogojapan

+0

Почему никто не рассматривает статичный бросок? ваши слова в порядке рассматривают этот код без статического актера, но ... здесь участвует статический актер ... – user2485710

+0

@ user2485710 «static_cast» только изменяет тип данных аргументов вызова функции. Но они не учитываются при определении того, какая перегрузка является более специализированной. Сравниваются только два шаблона - данные аргументы (литые или нет) не учитываются для этого решения. – jogojapan