Неявное преобразование C++ функции в указатель: какой компилятор прав? Clang и GCC не согласны

template <typename Type, Type Func>
struct A
{
};

void func();

A<void(), func> a; // same result with A<void(), &func> a;

Этот код компилируется с Clang (включая последнюю версию 8.0.0), но не с GCC (включая последнюю версию 9.1).

GCC говорит: error: 'void()' is not a valid type for a template non-type parameter

Какой компилятор прав и почему?

Обновлять

Я предполагаю, что GCC неверен, потому что следующее компилируется как в Clang, так и в GCC:

template <void()>
struct A
{
};

void func();

A<func> a; // same result with A<&func> a;

Таким образом, вопреки тому, что сообщает GCC в первом примере, void() кажется «допустимым типом для параметра шаблона, не являющегося типом».

Может быть актуально: A<void(*)(), func> a; работает

R2RT 07.06.2019 19:54

Я полагаю, что здесь нет указателей (только необработанные типы функций), и GCC прав. Здесь есть какое-то связанное объяснение о типе функции и указателе на функцию: stackoverflow.com/questions/8573763/… В любом случае, для конкретного ответа нам нужен языковой юрист. Обновлено: A<void(&)(), func> a; принимается обоими компиляторами, а A<void(&&)(), func> a; снова только clang

R2RT 07.06.2019 20:06

В обновлении тип параметра нетипового шаблона — void(*)(), потому что он скорректирован. template<void()> struct A эквивалентно template<void(*)()> struct A;демо

Oliv 07.06.2019 21:41
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
10
3
194
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Аналогично тому, что происходит с тип параметра функции, если тип параметра шаблона, не являющегося типом, является типом функции, он настраивается на указатель на тип функции [темп.парам]/8:

A non-type template-parameter of type “array of T” or of function type T is adjusted to be of type “pointer to T”.

Так что клан прав. Отчет об ошибке GCC уже существует ошибка №82773


Только текущий рабочий проект стандарта С++ распознает процесс замена аргумента шаблона в следующие параметры шаблона. Таким образом, можно утверждать, что стандарт не ясен, потому что он не указывает, что корректировка типа выполняется после каждой из этих замен.

Разница между Clang и GCC заключается в том, как они обрабатывают первый параметр шаблона, а не второй. Clang преобразовал первый параметр шаблона из void() в void(*)(), а GCC — нет.

Boris Rasin 07.06.2019 20:21

@BorisRasin Первый параметр void() в обоих случаях. Clang выполняет настройку параметра шаблона, отличного от типа, но не GCC. Я все еще копаюсь в стандарте, чтобы увидеть, должна ли корректировка типа также происходить в этом случае или нет, но я подозреваю, что это неясно.

Oliv 07.06.2019 20:26

Они оба точно так же регулируют второй параметр. Это имеет точно такой же результат: A<void(), &func>. Разница в том, как они обрабатывают первый параметр.

Boris Rasin 07.06.2019 20:29

@BorrisRasin Как я уже сказал, Clang не регулирует первый параметр. См. демо

Oliv 07.06.2019 21:14

Вы правы, Clang не настраивает первый параметр. Ваш ответ по-прежнему неверен, настройка второго параметра здесь ни при чем, так как проблема остается точно такой же с A<void(), &func>.

Boris Rasin 07.06.2019 21:21

@BorisRasin Вы путаете термин «аргумент» и термин «параметр». Первый параметр шаблона — Type, а связанный с ним аргумент — void(). Второй параметр — Func, связанный с ним аргумент — &func. После замены первого параметра связанным с ним аргументом во второй параметр тип второго параметра будет void(). Тип второго аргумента (&func) — void(*)() . Clang измените тип второго параметра с void() на void(*)(). Таким образом, тип аргумента &func соответствует типу параметра...

Oliv 07.06.2019 21:30

@BorisRasin ... Для GCC второй тип параметра не настроен на void(*)(), а параметр шаблона, не являющийся типом, не может иметь тип функции, поэтому GCC жалуется.

Oliv 07.06.2019 21:32

Я ничего не смешиваю. Шаблон имеет два параметра. Я называю одну из них first, а другую second. Итак, еще раз, когда параметр second указан как &func, он имеет явный тип void(*)(), поэтому настройка компилятора не требуется. Тем не менее, проблема сохраняется. Следовательно: настройка компилятором второго параметра шаблона не имеет отношения к проблеме.

Boris Rasin 07.06.2019 21:42

@BorisRasin Тип второго параметра, Func, не выводится из типа второго аргумента &func. Для вывода типа используйте auto. godbolt.org/z/-STKFd

Oliv 07.06.2019 21:51

Конечно, это не так. Никто не подсказал, что это. Как это вообще актуально?

Boris Rasin 07.06.2019 21:53

@BorisRasion Вы написали: «Еще раз, когда второй параметр указан как &func, он имеет явный тип void (*) ()». Что приводит к двум вариантам: либо вы смешиваете аргумент и параметр, либо считаете, что тип параметра выводится из типа аргумента. Теперь я думаю, что вы должны прочитать все это завтра.

Oliv 07.06.2019 21:56

Вы правы, я перепутал термины аргумент и параметр. Извини за это.

Boris Rasin 07.06.2019 22:09

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