Как неявное преобразование работает для параметров непигового шаблона?

Я предполагаю, что (неявные) неявные преобразования применяются при передаче параметров непигового шаблона. Например, для выражений типа std::array<int, 7> должно быть преобразование из int в std::size_t. Однако рассмотрим следующий код:

template <bool>
void f() {
    std::cout << "false\n";
}

template <>
void f<true>() {
    std::cout << "true\n";
}

int main() {
    f<1>();
    f<4>();
    f<0>();
}

Я ожидаю, что int будет неявно преобразован в bool здесь. Но поведение отличается от VC, GCC и clang.

В VC, true, false и false печатаются, что для меня действительно странно.

В GCC, true, true и false напечатаны, что я и ожидаю.

В то время как на clang код вообще не компилируется из-за оператора f<4>();.

шаблон кандидата игнорируется: недопустимый явно заданный аргумент для параметра 1-го шаблона

Итак, что говорит об этом стандарт? Что такое правило неявного преобразования для параметров шаблона непигового типа?

Ответ 1

Из стандарта (§14.3.2/5):

Следующие преобразования выполняются для каждого выражения, используемого в качестве шаблона-аргумента типа non-type. Если non-type template-argument не может быть преобразован в тип соответствующего шаблона-параметра, тогда программа плохо сформирована.

  • Для нестандартного шаблона-параметра интегрального или перечисляемого типа применяются преобразования, разрешенные в преобразованном постоянном выражении (5.19).

В §5.19 мы узнаем (подчеркнув мое):

Интегральное постоянное выражение представляет собой выражение интегрального или неперечисленного типа перечисления, неявно преобразованного на prvalue, где преобразованное выражение является основным постоянным выражением.... Преобразованное постоянное выражение type T - это выражение, неявно преобразованное в prvalue типа T, где преобразованное выражение является ядром постоянное выражение и неявная последовательность преобразования содержит только пользовательские преобразования, lvalue-to-rvalue конверсий (4.1), интегральных повышений (4.5) и интегральных преобразований (4.7) , кроме сужения конверсий (8.5.4). [Примечание: такие выражения могут использоваться в новых выражениях (5.3.4), как выражения case (6.4.2), как инициализаторы перечисления, если базовый тип является фиксированным (7.2), как границы массива (8.3.4) и как интегральные или перечисление аргументов шаблона non-type (14.3). -end note]

Таким образом, сужение конверсий (например, преобразование 4 в bool) явно запрещено для интегральных константных выражений, которые в этом случае необходимы как аргумент шаблона непигового типа. Это делает вызов f<4>() неправильным.

Я считаю, что Clang корректен при выдаче ошибки, а GCC и VC являются несоответствующими для того, чтобы не выдавать никаких диагностических данных.

[Обновить] Это Ошибка GCС# 57891, похоже, что он в настоящее время не назначен.