Явная функция-член объекта с параметром void

Согласно cppreference, начиная с C++23.

Для нестатической невиртуальной функции-члена, не объявленной с помощью cv-квалификатора или ref-квалификатора, ее первый параметр, если он не является пакетом параметров функции, может быть явным параметром объекта (обозначаемым префиксным ключевым словом this).

Может ли этот параметр иметь тип void? Текущие компиляторы допускают это, но различаются в вызове такой функции-члена:

struct A {
    void f(this void) {}
};

// ok everywhere
auto p = &A::f;

int main() {
    // ok in GCC and MSVC
    p();

    // ok in Clang
    A{}.f();
}

Кланг отклоняет p(); с помощью

ошибка: вызываемый тип объекта 'void (A::*)()' не является функцией или указателем на функцию

А GCC не любит A{}.f(); потому что

примечание: кандидат ожидает -1 аргументов, предоставлено 0

А также MSVC:

ошибка C2660: 'A::f': функция не принимает 0 аргументов

Онлайн-демо: https://gcc.godbolt.org/z/zMaqaTTav

Какой компилятор здесь прав?

Похожий вопрос, но про int, был задан несколько дней назад stackoverflow.com/questions/78739117/…

3CxEZiVlQ 20.07.2024 22:54

На прошлой неделе был еще один похожий вопрос: stackoverflow.com/questions/78733013

Remy Lebeau 20.07.2024 22:59

Лол, «кандидат ожидает -1 аргументов, предоставлено 0»

Caleth 29.07.2024 14:35
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
3
145
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Судя по тому, как написан стандарт в настоящее время, я бы склонен сказать, что именно Clang ведет себя правильно.

Согласно [dcl.fct]/3:

Список параметров, состоящий из одного безымянного параметра независимого типа void, эквивалентен пустому списку параметров.

Ключевое слово this не влияет на тип параметра, который по-прежнему void и остается безымянным. Поскольку он не находится внутри шаблона, он также тривиально не зависит.

Остальная часть [dcl.fct] предполагает, что эта корректировка объявления была сделана без повторного упоминания об этом явно, например, при определении типа функции в [dcl.fct]/5.

Поэтому я думаю, что [dcl.fct]/6, который определяет эффект this в объявлении параметра для объявления явного параметра объекта, также следует учитывать после void-корректировки.

Затем, поскольку объявление параметра this void было удалено из списка, функция является не явной объектной функцией, а неявной объектной функцией без каких-либо параметров.

Тип функции будет void() и &A::f, тогда формируется указатель на член типа void (*A::f)(). Вызов указателя члена с помощью синтаксиса вызова функции p() невозможен.

Однако вызов нестатической функции-члена с выражением доступа к члену A{}.f() возможен. this в определении функции будет указывать на временный объект, материализованный из A{}. Аргументы вызова не нужны, поскольку f не имеет параметров.

Однако я не уверен, действительно ли это желательное поведение. Специальная настройка [dcl.fct]/3 существует только для обратной совместимости C. Нет необходимости расширять его до this void, что в любом случае недопустимо в C. Вместо этого я думаю, что его следует сделать некорректным, как и все другие варианты использования (с учетом cv) void параметров.

В любом случае поведение GCC и MSVC не имеет смысла. Даже если this void по-прежнему приводит к тому, что функция является явной объектной функцией и не имеет неправильного формата, тогда, независимо от того, считается ли this void фактическим параметром, остальные спецификации стандарта не будут согласованными. Либо это будет явная объектная функция без явного объектного параметра, который, однако, необходимо инициализировать при вызовах. Или это может быть функция с параметром void, которую необходимо инициализировать, но объектов void вообще не существует.

Это CWG2915, который предлагает сделать программу(void f(this void);) некорректной.

От CWG2915:

Изменить пункт 3 9.3.4.6 [dcl.fct] следующим образом:

Если предложение объявления параметра пусто, функция не принимает аргументов. Список параметров, состоящий из одного безымянного необъектного параметра независимого типа void, эквивалентен пустому списку параметров. За исключением этого особого случая, параметр не должен иметь тип cv void.

(выделено мной)

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