С++ перегрузите оператор дважды, один возвращает неконстантную ссылку и другую ссылку на константу, каково предпочтение?

Я дважды перегружаю оператор с тем же списком параметров. но с другим типом возврата:

T& operator()(par_list){blablabla}    
const T& operator()(par_list){blablabla}

Итак, когда я вызываю оператор(), какая функция будет вызываться на основе каких предпочтений или ситуации? Я знаю, что если я вызываю() при функции const, это должен быть const T & один.

Мне просто интересно, как С++ справляется с такой ситуацией и как работает настройка по умолчанию.

Спасибо

Ответ 1

Эти функции не перегружают друг друга; они имеют одинаковые сигнатуры, и поэтому попытка переопределить ту же функцию, которая является ошибкой. Тип возврата не является частью сигнатуры функции. Чтобы перегрузить функцию, вы должны объявить вторую функцию с тем же именем, но разные параметры или const/volatile квалификаторы, то есть квалификаторы функции, а не тип возврата.

(Они не переопределяют друг друга; переопределение - это то, что производные классы выполняют с виртуальными функциями своих базовых классов).

Общепринято определение перегрузки const и не const функции-члена; перегрузка const должна объявить функцию const, а не только тип возвращаемого значения:

T& operator()(par_list){blablabla}
const T& operator()(par_list) const {blablabla}
                              ^^^^^

Теперь первый вызов будет вызываться, если вы примените () к объекту не const, а второй - к объекту const. Например:

Thingy nc;
Thingy const c;

nc(); // calls the first (non-const) overload
c();  // calls the second (const) overload

Ответ 2

Вы не можете перегружать функцию/метод на основе типа возврата. Я ожидаю, что компилятор будет здесь делать ошибку. Что вы можете сделать, так это указать метод как метод const, используя

const T& operator()(par_list) const {blahblah}

Квалификатор const не только означает, что это можно вызвать в приемнике const, но также используется в разрешении перегрузки. Это происходит потому, что это влияет на неявный параметр *this, который передается методу; a const использует квалификатор const на *this, а квалификаторы const учитываются при разрешении перегрузки.

Ответ 3

То, как вы определяете своих операторов, никак не может решить, какой оператор() вызывать. Перегрузка функций (и операторов) может выполняться только по типу аргументов, а не по типу возврата. И на самом деле у вас будет ошибка при компиляции, как только вы определите вторую, компилятор, считая, что вы переопределяете одну и ту же функцию/оператор.

Однако, общее (и, вероятно, то, что у вас есть):

T& operator()(par_list){blablabla}
const T& operator()(par_list) const {blablabla}

Этот дополнительный "const" после списка аргументов существует, потому что вы определяете нестатические функции-члены, а функции-члены имеют неявный скрытый аргумент: указатель "this" для экземпляра класса. Ключевое слово "const" указывает, является ли этот скрытый указатель экземпляром const или нет. Этот аргумент участвует в разрешении перегрузки, и именно в этом случае используется компилятор для выбора той версии используемого оператора.

Итак:

class A {
    T& operator()() { ... }
    const T& operator()() const { .... }
};

A a;
const A& ca(a);
a(); -> returns a T&
ca(); -> returns a const T&