Разрешение перегрузки между обычными и явными функциями-членами объекта

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

struct A {
    int f() { return 1; }
};

struct B : A {
    using A::f;
    int f(this A) { return 2; }
};

int main() {
    return B{}.f();
}

Какую функцию необходимо выбрать при разрешении перегрузки?

GCC и MSVC предпочитают обычную функцию-член f(), и программа возвращает 1.

Но Clang делает противоположный выбор, выбирая явную функцию-член объекта f(this A), и программа возвращает 2.

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

Какой компилятор здесь правильный, если таковой имеется (почему бы не неоднозначность разрешения перегрузки)?

«Какой компилятор здесь правильный, если таковой имеется (почему бы не неоднозначность разрешения перегрузки)?...» GCC и msvc верны, потому что вызов неявной функции-члена не требует преобразования.

user12002570 22.07.2024 18:33

«почему бы не неоднозначность разрешения перегрузки» - Связано: CWG 2789

Remy Lebeau 22.07.2024 18:38

Вы также можете увидеть это напрямую, добавив вектор копирования для класса A и заметив, что clang неправильно использует вектор копирования, а gcc и msvc — нет. Демо

user12002570 22.07.2024 18:50

Я думаю, если бы вы написали int f(this B) вместо int f(this A), это должно было бы быть двусмысленно, но, похоже, только MSVC придерживается такого же мнения: gcc.godbolt.org/z/W7Yd4Eved

user17732522 22.07.2024 19:05

Вот отчет об ошибке clang

user12002570 22.07.2024 19:12
Стоит ли изучать 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
5
98
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

тлдр; Clang ошибся в выборе явной функции-члена объекта по причинам, описанным ниже. Вот подтвержденная ошибка с звоном.

Какой компилятор здесь правильный, если таковой имеется (почему бы не неоднозначность разрешения перегрузки)?

Прежде всего обратите внимание, что согласно over.match.func.general, функция, назначенная using A::f, считается членом производного класса с целью определения типа неявного параметра объекта.

Это означает, что для вызова B{}.f() лучше подходит неявная функция-член объекта, поскольку она не требует преобразования аргумента B{}.

Для справки вот over.match.func.general, в котором говорится:

Для функций без преобразования, введенных с помощью объявления using в производный класс, функция считается членом производного класса с целью определения типа неявного параметра объекта.


Мы также можем увидеть это, добавив вектор копирования для класса A и заметив, что clang неправильно использует вектор копирования для преобразования, а gcc и msvc — нет. Демо

Таким образом, gcc и msvc правы, выбрав неявную версию, которую сделал видимой using A::f;.


Вот подтвержденная ошибка clang:

Clang выбирает неправильную перегрузку, когда задействованы явные и неявные функции-члены

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