Перегрузка по типу возврата

Я прочитал несколько вопросов здесь на SO по этой теме, которая кажется мне еще запутанной. Я только начал изучать C++ и еще не изучал шаблоны или перегрузку операторов и тому подобное.

Есть ли простой способ перегрузки?

class My {
public:
    int get(int);
    char get(int);
}

без шаблонов или странного поведения? или я должен просто

class My {
public:
    int get_int(int);
    char get_char(int);
}

?

8 ответов

Решение

Нет, нет Вы не можете перегружать методы, основанные на типе возвращаемого значения.

Разрешение перегрузки учитывает сигнатуру функции. Подпись функции состоит из:

  • имя функции
  • CV-классификаторы
  • типы параметров

И вот цитата:

1.3.11 подпись

информация о функции, которая участвует в разрешении перегрузки (13.3): ее список параметров-типов (8.3.5) и, если функция является членом класса, cv-квалификаторы (если таковые имеются) для самой функции и класса в котором функция-член объявлена. [...]

Опции:

1) изменить название метода:

class My {
public:
    int getInt(int);
    char getChar(int);
};

2) выходной параметр:

class My {
public:
    void get(int, int&);
    void get(int, char&);
}

3) шаблоны... перебор в этом случае.

Это возможно, но я не уверен, что эту технику я бы порекомендовал новичкам. Как и в других случаях, когда вы хотите, чтобы выбор функций зависел от того, как используется возвращаемое значение, вы используете прокси; сначала определите функции, такие как getChar а также getIntто общий get() который возвращает прокси как это:

class Proxy
{
    My const* myOwner;
public:
    Proxy( My const* owner ) : myOwner( owner ) {}
    operator int() const
    {
        return myOwner->getInt();
    }
    operator char() const
    {
        return myOwner->getChar();
    }
};

Расширьте его на столько типов, сколько вам нужно.

Как уже говорилось ранее, шаблонов в этом случае слишком много, но об этом все же стоит упомянуть.

class My {
public:
    template<typename T> T get(int);
};

template<> int My::get<int>(int);
template<> char My::get<char>(int);

Нет, вы не можете перегружать типом возвращаемого значения; только по типам параметров и константным /volatile квалификаторам.

Одной из альтернатив будет "возврат" с использованием ссылочного аргумента:

void get(int, int&);
void get(int, char&);

хотя я бы, вероятно, использовал бы шаблон или функции с другими именами, как во втором примере.

Воскрешение старого потока, но я вижу, что никто не упоминал о перегрузке с помощью квалификаторов ref. Ref-qualifiers- это языковая функция, добавленная в C++11, и я только недавно наткнулся на нее - она ​​не так широко распространена, как, например, cv-qualifiers. Основная идея состоит в том, чтобы различать два случая: когда функция-член вызывается для объекта rvalue, и когда вызывается для объекта lvalue. Вы можете написать что-то вроде этого (я немного изменяю код OP):

#include <stdio.h>

class My {
public:
    int get(int) & { // notice &
        printf("returning int..\n");
        return 42;
    }
    char get(int) && { // notice &&
        printf("returning char..\n");
        return 'x';
    };
};

int main() {
    My oh_my;
    oh_my.get(13); // 'oh_my' is an lvalue
    My().get(13); // 'My()' is a temporary, i.e. an rvalue
}

Этот код выдаст следующий результат:

returning int..
returning char..

Конечно, как и в случае с cv-квалификаторами, обе функции могли вернуть один и тот же тип, и перегрузка все равно будет успешной.

Вы можете думать так:

У тебя есть:

  int get(int);
  char get(int);

И не обязательно собирать возвращаемое значение функции при вызове.

Теперь вы вызываете

  get(10);  -> there is an ambiguity here which function to invoke. 

Таким образом, нет смысла, если перегрузка разрешена в зависимости от типа возвращаемого значения.

Хотя большинство других комментариев по этой проблеме технически правильны, вы можете эффективно перегрузить возвращаемое значение, если объедините его с перегрузкой входного параметра. Например:

class My {
public:
    int  get(int);
    char get(unsigned int);
};

DEMO:

#include <stdio.h>

class My {
public:
    int  get(         int x) { return 'I';  };
    char get(unsinged int x) { return 'C';  };
};

int main() {

    int i;
    My test;

    printf( "%c\n", test.get(               i) );
    printf( "%c\n", test.get((unsigned int) i) );
}

Результатом этого является:

I 
C

Вы не можете перегружать методы, основанные на возвращаемых типах. Лучше всего создать две функции с немного отличающимся синтаксисом, например во втором фрагменте кода.

В C++ нет способа перегрузки по типу возвращаемого значения. Без использования шаблонов, используя get_int а также get_char будет лучшим, что вы можете сделать.

Я использовал ответ Джеймса Канце, используя прокси:

/questions/6848474/peregruzka-po-tipu-vozvrata/6848481#6848481

Я хотел избежать использования множества уродливых static_cast в void*, поэтому сделал следующее:

#include <SDL_joystick.h>
#include <SDL_gamecontroller.h>

struct JoyDev {
    private:
        union {
            SDL_GameController* dev_gc = nullptr;
            SDL_Joystick*       dev_js;
        };
    public:
        operator SDL_GameController*&() { return dev_gc; }
        operator SDL_Joystick*&()       { return dev_js; }

        SDL_GameController*& operator=(SDL_GameController* p) { dev_gc = p; return dev_gc; }
        SDL_Joystick*&       operator=(SDL_Joystick* p)       { dev_js = p; return dev_js; }
};

struct JoyState {
    public:
        JoyDev dev;
};

int main(int argc, char** argv)
{
    JoyState js;

    js.dev = SDL_JoystickOpen(0);

    js.dev = SDL_GameControllerOpen(0);

    SDL_GameControllerRumble(js.dev, 0xFFFF, 0xFFFF, 300);

    return 0;
}

Прекрасно работает!

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

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