Автоматический вывод параметров шаблона C++ не работает в GCC 14, в отличие от его более старых версий и Clang

Следующий фрагмент принимается GCC 13 и старше, а также всеми версиями Clang, но не GCC 14. Любое из двух предложенных изменений заставляет GCC 14 также принимать код.

#include <iostream>

template <int T> struct A { int value = T; };

// Replacing 'unsigned char' with 'int' makes it work with GCC 14:
template <unsigned char X> using B = A<X>;

// Or, replacing 'auto' with 'int' makes it work with GCC 14:
template <auto X>
void foo(B<X>& mat) noexcept
{
    std::cout << mat.value << "\n";
}

int main()
{
    A<2> mat;
    foo(mat);
}

Ошибка, выдаваемая GCC 14, заключается в следующем: параметр шаблона auto не может быть выведен, если auto не заменен на определенный тип или параметр шаблона, не относящийся к типу, псевдонима имеет тот же тип, что и шаблон с псевдонимом:

<source>: In function 'int main()':
<source>:18:8: error: no matching function for call to 'foo(A<2>&)'
   18 |     foo(mat);
      |     ~~~^~~~~
<source>:10:6: note: candidate: 'template<auto X> void foo(B<((unsigned char)X)>&)'
   10 | void foo(B<X>& mat) noexcept
      |      ^~~
<source>:10:6: note:   template argument deduction/substitution failed:
<source>:18:8: note:   couldn't deduce template parameter 'X'
   18 |     foo(mat);
      |     ~~~^~~~~

Какой компилятор правильный?

gcc прав, отклонив его. Неявное преобразование типов не следует использовать при распознавании типов шаблонов.

Pepijn Kramer 03.08.2024 20:08

@PepijnKramer Спасибо! Можно, пожалуйста, ссылку на спецификацию?

Pavel Kirienko 03.08.2024 20:10

Например, см. этот ответ: Неявное преобразование типов с шаблонными параметрами функции (но для всех шаблонов применяются одни и те же правила)

Pepijn Kramer 03.08.2024 20:13

Я склонен думать, что gcc неверен, потому что template<auto X> следует вывести как template<int X>, и в этот момент проблем нет: godbolt.org/z/aGeaK4aG3

Gene 03.08.2024 20:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
73
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Он должен скомпилироваться. Параграф 13.4.3/2 описывает вывод аргументов:

Значение нетипового параметра шаблона P (возможно, выведенное) тип T определяется на основе аргумента шаблона A следующим образом. Если Т не тип класса и A не является списком инициализации в скобках, A должен быть преобразованное постоянное выражение (7.7) типа Т; значение P равно A (так как преобразовано)

Процесс конвертации описан в 7.7/13:

Преобразованное константное выражение типа T является выражением, неявно преобразуется в тип T, где преобразованное выражение является константой выражение, а последовательность неявного преобразования содержит только <skiped...>

интегральные преобразования (7.3.9), кроме сужающих преобразований (9.4.5),

Описание сужающих конверсий мы находим в 9.4.5/7, где также подробно описано, какие конверсии из этого исключены:

Сужающее преобразование — это неявное преобразование... (7.4) — от целочисленного типа или типа перечисления без области видимости к целочисленному типу, который не может представлять все значения исходного типа, за исключением случаев, когда (7.4.1) — источником является битовое поле, ширина которого w меньше ширины его тип (или, для типа перечисления, его базовый тип) и целевой тип может представлять все значения гипотетического расширенного целочисленный тип шириной w и с той же подписью, что и оригинал тип или (7.4.2) — источником является постоянное выражение, значение которого после комплексного продвижения будет соответствовать целевому типу

Последний маркер описывает текущий случай: целочисленное значение 2 соответствует целевому типу unsigned char, поэтому оно исключено из сужающих ограничений преобразования.

Другие вопросы по теме