Перегрузка по типу возврата
Я прочитал несколько вопросов здесь на 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;
}
Прекрасно работает!
Вы не можете перегружать функцию в зависимости от типа возвращаемого значения функции. Вы можете переопределить в зависимости от типа и количества аргументов, которые принимает эта функция.