반환 유형별 오버로딩


81

나는 아직 나에게 혼란스러워 보이는이 주제에 대해 몇 가지 질문을 읽었습니다. 저는 방금 C ++를 배우기 시작했고 아직 템플릿이나 연산자 오버로딩 등을 연구하지 않았습니다.

이제 과부하하는 간단한 방법이 있습니다.

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

템플릿이나 이상한 행동없이? 아니면 그냥

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

?



1
@AdamV, 나는 당신의 의견을 정말 좋아합니다. 짧지 만 완전히 단단합니다.
Pouya

@Adam V 실제로 과부하 된 함수의 주소를 사용하는 것과 같은 모호성이 이미 있습니다. 이 경우 표현식에 대한 유형 기대가 있어야합니다. 하나가 없으면 프로그램이 잘못 구성되었습니다. 그리고 이것은 이미 구현되었습니다. 반환 형식으로 함수 오버로딩을 구현하는 데 동일한 규칙을 사용하는 것은 그리 어렵지 않을 것이라고 생각합니다. 따라서 구체적인 예에서 모호성은 반환 된 유형의 캐스트로 제거됩니다. 로 인스턴스화 int반환 값은 다음과 같이 표시됩니다 (int)get(9)와 함께 char이 같은 (char)get(9).
AnArrayOfFunctions

여기에 도달하면 Luchian이 제안한 두 가지 다른 기능 이름을 생각하는 것이 최선의 선택이라고 생각합니다.
Kemin Zhou

답변:


101

아니에요. 반환 유형에 따라 메서드를 오버로드 할 수 없습니다.

오버로드 해결은 함수 서명 을 고려합니다 . 함수 서명은 다음으로 구성됩니다.

  • 기능 명
  • 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) 템플릿 ...이 경우 과잉.


17
반환 유형에 대해 일반 함수를 오버로드 할 수는 없지만 컴파일러는 결과 유형에 따라 변환 연산자 중에서 선택합니다. 이를 활용하여 반환 유형에 과부하가 걸린 것처럼 효과적으로 작동하는 프록시를 만들 수 있습니다.
James Kanze 2012 년

2
@JeffPigarelli 템플릿 솔루션은 멤버 템플릿을 의미합니다 : My::get<T>(int). 유효한 대안입니다 _if 1) 모두 동일한 기본 코드 (예 :) 를 사용하여 다양한 유형을 처리해야합니다 (예 : boost::lexical_cast<T>( someStringValue )또는 다른 템플릿에서 이러한 함수를 호출 할 수 있어야합니다 ( myMy.get<T>( i ), T는이 다른 템플릿의 인수입니다). . Luchian 말한대로 그렇지 않으면, 그들은 과잉입니다.
제임스 간제

39
있습니다 이유 는 과부하 반환 유형을 기반으로 할 수는 C ++에서는 함수 호출의 값을 폐기 할 수 있다는 것입니다. 따라서 단순히 my.get(0);컴파일러 를 호출 하면 실행할 코드를 결정할 방법이 없습니다.
benzado 2012 년

9
이 경우 @benzado, 그것은 그러한 경우 컴파일러 오류가 발생한다 그것은에서와 같이, 그렇지 않으면 유형을 추론한다 그래서 이미 많은 다른 시나리오.
rr-

2
같은 이유로 @benzado는 void foo(int x = 0) {} void foo(double x = 0) {}허용되지 않아야합니다. 그러나 그렇지 않습니다. 만 컴파일러는 정말 (구별 할 수없는 경우 foo()오류 얻을 것이다)
largest_prime_is_463035818

82

가능하지만 초보자에게 추천 할 수있는 기술인지는 잘 모르겠습니다. 다른 경우와 마찬가지로 반환 값이 사용되는 방식에 따라 함수를 선택하려면 프록시를 사용합니다. 처음처럼 함수를 정의 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();
    }
};

필요한만큼 많은 유형으로 확장하십시오.


10
+1, 코너 케이스이지만 변환 연산자는 실제로 반환 유형에 과부하가 걸리며 모든 곳에서이 기능을 얻는 데 활용할 수 있습니다.
Matthieu M.

3
@MatthieuM. 거의 모든 곳에 있지만 암시 적 변환에 대한 일반적인 경고가 있습니다. 그렇지 않으면 존재하지 않을 모호성을 도입 할 위험이 있습니다. 그러나 프록시의 경우 위험이 경미하다고 생각합니다. 암시 적 변환을 원하는 경우 외에는 프록시 유형의 인스턴스가 없을 것입니다. 또한 프록시의 전환은 사용자 정의 전환 하나로 계산됩니다. 필요한 경우 std::string프록시가을 제공 operator char const*()하는 경우 작동하지 않습니다.
James Kanze 2012 년

여기서 프록시를 사용하는 이유는 프록시가 필수 인 경우를 생각할 수 없습니다. 하나 제공 할 수 있습니까? 감사!
陳力

8

아니요, 반환 유형으로 오버로드 할 수 없습니다. 매개 변수 유형 및 const / volatile 한정자에 의해서만.

한 가지 대안은 참조 인수를 사용하여 "반환"하는 것입니다.

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

나는 아마도 템플릿을 사용하거나 두 번째 예제와 같이 다른 이름의 함수를 사용할 것입니다.


반환 유형이 int오류 코드 인 EFI API .
Cole Johnson

1
주의하세요. char 및 int 유형은 암시 적으로 변환 될 수 있습니다.
Kemin Zhou

5

다음과 같이 생각할 수 있습니다.

당신은 :

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

그리고 호출하는 동안 함수의 반환 값을 수집하는 것은 필수가 아닙니다.

이제 당신은

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

따라서 반환 유형에 따라 오버로딩이 허용되면 의미가 없습니다.


4

오래된 스레드를 부활 시켰지만 아무도 ref 한정자에 의한 오버로딩을 언급하지 않았다는 것을 알 수 있습니다. Ref-qualifier는 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 한정자의 경우와 마찬가지로 두 함수 모두 동일한 유형을 반환 할 수 있으며 오버로딩은 여전히 ​​성공적입니다.


4

앞서 언급했듯이 템플릿은이 경우 과잉이지만 여전히 언급 할 가치가있는 옵션입니다.

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

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

3

이 문제에 대한 다른 의견의 대부분은 기술적으로 정확하지만, 당신은 할 수 효과적으로 반환 값 과부하 경우 는 입력 매개 변수를 오버로드와 결합. 예를 들면 :

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

데모:

#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

6
함수 시그니처를 완전히 변경하므로 반환 유형에 의해 오버로딩되지 않고 단순히 오버로딩됩니다
Dado

이 메서드를 성공적으로 사용하여 프로덕션을 실행하는 C ++ JSON API에 대한 다양한 값을 반환했습니다. 잘 했어! 기술적으로는 반환 유형에 의해 오버로딩되지 않지만 동일한 함수 이름을 가진 다른 반환 유형의 의도를 달성하고 유효하고 명확한 C ++이며 오버 헤드가 거의 없습니다 (함수 호출에서 단일 변수 인스턴스화).
guidotex

이것은 리턴 유형에 의한 과부하가 아니지만 작업을 수행합니다. 나를 "비열한"라고합니다
마커스

2

C ++에서 반환 유형으로 오버로드하는 방법은 없습니다. 템플릿을 사용하지 않고, 사용 get_int하고 get_char당신이 할 수있는 최선이 될 것입니다.


확실히하기 위해 : 뭔가 template <class T> T get(int)작동할까요?
Niklas B.

4
예, @Niklas,하지만 당신은 그것을 호출해야 할 것 get<int>get<char>정말 많이 이상을 얻을하지 않는, get_int그리고 get_char경우 다른 템플릿 기능을 사용하지 않는 것입니다.
Rob Kennedy

@Rob : 글쎄요, 컴파일러는 T당신이 T get(T). 를 호출 get('a')하면 컴파일러 T는이를 a로 추론하고 char명시 적으로 호출 할 필요가 없습니다 get<char>('a'). 나는 그것이 표준이라고 생각하지만 여전히 이것이 표준인지 확실하지 않습니다. 참고로 GCC와 Clang이 모두이를 지원합니다.
netcoder

1
그것은 완벽하게 표준 @Netcoder이지만 컴파일러가 단지 반환 유형을 추론하는 경우는 아닙니다. 귀하의 예제에서 컴파일러는 인수 유형을 추론하고,이를 알게 T되면 반환 유형을 포함하여 다른 모든 곳 의 값을 채 웁니다 . TNiklas의 첫 번째 주석에서 함수를 추론하는 컴파일러의 예를 제공하기를 기대했습니다 .
Rob Kennedy

2

반환 형식을 기반으로 메서드를 오버로드 할 수 없습니다. 가장 좋은 방법은 두 번째 코드 스 니펫과 같이 구문이 약간 다른 두 개의 함수를 만드는 것입니다.


0

함수의 반환 유형에 따라 함수를 오버로드 할 수 없습니다. 이 함수가 취하는 인수의 유형과 수에 따라 오버 리딩 할 수 있습니다.


0

프록시를 사용하여 James Kanze의 답변을 사용했습니다.

https://stackoverflow.com/a/9569120/262458

나는 void *에 추악한 static_cast를 많이 사용하는 것을 피하고 싶었 기 때문에 이렇게했습니다.

#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;
}

완벽하게 작동합니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.