문제

더 많은 주류 정적으로 입력 한 언어가 반환 유형별로 기능/메소드 과부하가되지 않는 이유는 무엇입니까? 나는 그 일을 생각할 수 없다. 매개 변수 유형별 오버로드를 지원하는 것보다 유용하거나 합리적이지 않은 것 같습니다. 어떻게 덜 인기가 있습니까?

도움이 되었습니까?

해결책

다른 사람들의 말과는 반대로, 반환 유형에 의한 과부하 ~이다 가능하고 ~이다 현대 언어로 이루어집니다. 일반적인 반대는 코드와 같은 것입니다

int func();
string func();
int main() { func(); }

당신은 어느 것을 말할 수 없습니다 func() 호출되고 있습니다. 이것은 몇 가지 방법으로 해결 될 수 있습니다.

  1. 그러한 상황에서 호출되는 기능을 결정하는 예측 가능한 방법이 있습니다.
  2. 이러한 상황이 발생할 때마다 컴파일 타임 오류입니다. 그러나 프로그래머가 명확하게 표현할 수있는 구문이 있습니다. int main() { (string)func(); }.
  3. 부작용이 없습니다. 부작용이없고 함수의 반환 값을 사용하지 않으면 컴파일러는 처음에 함수를 호출하지 않을 수 있습니다.

내가 정기적으로 두 가지 언어 (AB) 반환 유형별로로드 사용 : 그리고 Haskell. 그들이 무엇을하는지 설명하겠습니다.

~ 안에 , 간에는 근본적인 차이가 있습니다 스칼라 그리고 목록 맥락 (및 다른 사람들이지만 우리는 두 개가있는 척 할 것입니다). Perl의 모든 내장 기능은 문맥 여기에서 호출됩니다. 예를 들어, join 운영자는 컨텍스트를 나열하는 동안 scalar 운영자는 스칼라 컨텍스트를 강제로 비교하므로 비교합니다.

print join " ", localtime(); # printed "58 11 2 14 0 109 3 13 0" for me right now
print scalar localtime(); # printed "Wed Jan 14 02:12:44 2009" for me right now.

Perl의 모든 연산자는 스칼라 컨텍스트에서 무언가를 수행하고 목록 컨텍스트에서 무언가를 수행하며 설명 된대로 다를 수 있습니다. (이것은 임의의 연산자와 같은 것이 아닙니다 localtime. 배열을 사용하는 경우 @a 목록 컨텍스트에서는 배열을 반환하고 스칼라 컨텍스트에서는 요소 수를 반환합니다. 예를 들어 print @a 요소를 인쇄합니다 print 0+@a 크기를 인쇄합니다.) 또한 모든 운영자는 컨텍스트, 예를 들어 추가 + 스칼라 컨텍스트를 강요합니다. 모든 항목 man perlfunc 이것을 문서화합니다. 예를 들어, 다음은 항목의 일부입니다. glob EXPR:

목록 컨텍스트에서 값에 대한 파일 이름 확장 목록을 반환합니다. EXPR 표준 유닉스 쉘과 같은 /bin/csh 할것이다. 스칼라 컨텍스트에서 글로그는 이러한 파일 이름 확장을 통해 반복되어 목록이 소진 될 때 undef를 반환합니다.

이제 목록과 스칼라 컨텍스트의 관계는 무엇입니까? 잘, man perlfunc 말한다

다음과 같은 중요한 규칙을 기억하십시오. 목록 컨텍스트에서 표현식의 동작을 스칼라 컨텍스트에서 동작과 관련이 있거나 그 반대도 마찬가지입니다. 완전히 다른 두 가지 일을 할 수 있습니다. 각 연산자와 기능은 스칼라 컨텍스트에서 반환하는 것이 가장 적합한 값을 결정합니다. 일부 연산자는 목록 컨텍스트에서 반환 된 목록의 길이를 반환합니다. 일부 연산자는 목록에서 첫 번째 값을 반환합니다. 일부 연산자는 목록의 마지막 값을 반환합니다. 일부 운영자는 성공적인 운영 수를 반환합니다. 일반적으로 일관성을 원하지 않는 한 원하는대로합니다.

따라서 단일 함수를 갖는 것은 간단한 문제가 아니며 마지막에 간단한 변환을 수행합니다. 사실, 나는 선택했다 localtime 이런 이유로 예.

이 행동을 가진 것은 단지 내장이 아닙니다. 모든 사용자는 이러한 기능을 사용하여 정의 할 수 있습니다 wantarray,이를 통해 목록, 스칼라 및 공극 컨텍스트를 구별 할 수 있습니다. 예를 들어, 무효 상황에서 호출되는 경우 아무것도하지 않기로 결정할 수 있습니다.

이제 이것이 그렇지 않다고 불평 할 수 있습니다 진실 반환 값별로로드 된 기능은 하나의 함수 만 가지고 있기 때문에 컨텍스트가 호출 된 다음 해당 정보에 따라 행동합니다. 그러나 이것은 분명히 동일합니다 (그리고 Perl이 문자 그대로 일반적인 과부하를 허용하지 않는 방법과 유사하지만 함수는 그 주장을 조사 할 수 있습니다). 더욱이, 그것은이 응답의 시작 부분에서 언급 된 모호한 상황을 잘 해결합니다. Perl은 어떤 방법을 호출할지 모른다고 불평하지 않습니다. 그것은 단지 그것을 부릅니다. 기능이 어떤 컨텍스트를 호출했는지 알아내는 것입니다. 항상 가능합니다.

sub func {
    if( not defined wantarray ) {
        print "void\n";
    } elsif( wantarray ) {
        print "list\n";
    } else {
        print "scalar\n";
    }
}

func(); # prints "void"
() = func(); # prints "list"
0+func(); # prints "scalar"

(참고 : 때때로 기능을 의미 할 때 Perl 연산자라고 말할 수도 있습니다. 이것은이 토론에 중요하지 않습니다.)

Haskell 부작용이없는 다른 접근법을 취합니다. 또한 강력한 유형 시스템이 있으므로 다음과 같은 코드를 작성할 수 있습니다.

main = do n <- readLn
          print (sqrt n) -- note that this is aligned below the n, if you care to run this

이 코드는 표준 입력에서 부동 소수점 번호를 읽고 제곱근을 인쇄합니다. 그러나 이것에 대해 놀라운 점은 무엇입니까? 글쎄, 유형 readLn ~이다 readLn :: Read a => IO a. 이것이 의미하는 바는 모든 유형의 경우 Read (공식적으로, 인스턴스 인 모든 유형 Read 유형 클래스), readLn 읽을 수 있습니다. Haskell은 내가 부동산 지점 번호를 읽고 싶다는 것을 어떻게 알았습니까? 글쎄, 유형 sqrt ~이다 sqrt :: Floating a => a -> a, 그것은 본질적으로 그것을 의미합니다 sqrt 부동 소수점 번호 만 입력으로 만 허용 할 수 있으므로 Haskell은 내가 원하는 것을 추론했습니다.

Haskell이 내가 원하는 것을 추론 할 수 없을 때 어떻게됩니까? 글쎄, 몇 가지 가능성이 있습니다. 반환 값을 전혀 사용하지 않으면 Haskell은 단순히 기능을 호출하지 않습니다. 그러나 내가한다면 하다 반환 값을 사용하면 Haskell은 유형을 유추 할 수 없다고 불평합니다.

main = do n <- readLn
          print n
-- this program results in a compile-time error "Unresolved top-level overloading"

원하는 유형을 지정하여 모호성을 해결할 수 있습니다.

main = do n <- readLn
          print (n::Int)
-- this compiles (and does what I want)

어쨌든,이 전체 논의는 반품 값에 의한 과부하가 가능하고 이루어지며 질문의 일부에 응답한다는 것입니다.

질문의 다른 부분은 왜 더 많은 언어가 그렇게하지 않는지입니다. 다른 사람들이 대답하게하겠습니다. 그러나 몇 가지 의견은 : 원칙적인 이유는 아마도 혼란의 기회가 인수 유형에 의한 과부하보다 진정으로 더 크기 때문일 것입니다. 개별 언어의 근거를 볼 수도 있습니다.

아다: "가장 간단한 오버로드 해상도 규칙은 과부하 된 참조를 해결하기 위해 가능한 한 넓은 컨텍스트의 모든 정보 (모든 정보)를 사용하는 것 같습니다.이 규칙은 간단 할 수 있지만 도움이되지 않습니다. 인간 독자가 필요합니다. 임의로 큰 텍스트 조각을 스캔하고 임의로 복잡한 추론 (위의 (g)와 같은)를 만들기 위해 더 나은 규칙은 인간 독자 또는 컴파일러가 수행 해야하는 작업을 명시 적으로 만들고이 작업을 수행하는 것입니다. 가능한 한 인간 독자에게 자연스럽게. "

C ++ (Bjarne Stroustrup의 "C ++ 프로그래밍 언어"의 7.4.1 항) : "반환 유형은 과부하 해상도에서 고려되지 않습니다. 그 이유는 개별 연산자 또는 기능 호출 컨텍스트 독립성에 대한 해상도를 유지하는 것입니다. 고려 사항 : 고려하십시오.

float sqrt(float);
double sqrt(double);

void f(double da, float fla)
{
    float fl = sqrt(da);     // call sqrt(double)
    double d = sqrt(da); // call sqrt(double)
    fl = sqrt(fla);            // call sqrt(float)
    d = sqrt(fla);             // call sqrt(float)
}

반환 유형을 고려한 경우 더 이상 전화를 볼 수 없습니다. sqrt() 분리하여 어떤 함수가 호출되었는지 결정합니다. "(비교를 위해 Haskell에는 없음 절대적인 전환.)

자바 (Java 언어 사양 9.4.1) : "상속 된 방법 중 하나는 다른 상속 된 방법에 대해 대체 가능한 반환 유형이어야합니다. 그렇지 않으면 컴파일 타임 오류가 발생합니다." (그렇습니다. 이것이 이론적 근거를주지 않는다는 것을 알고 있습니다. 나는 "Java 프로그래밍 언어"로 Gosling에 의해 이론적 근거가 주어질 것이라고 확신합니다. 아마 누군가가 사본을 가지고있을 것입니다. 나는 그것이 본질적으로 "최소한의 놀라움의 원칙"이라고 확신합니다. ) 그러나 Java에 대한 재미있는 사실 : JVM 허용 반환 값으로 과부하! 예를 들어, 이것은 사용됩니다 스칼라, 접근 할 수 있습니다 Java를 통해 직접 내부와 함께 놀면서도.

추신. 마지막으로, 실제로 C ++의 리턴 값으로 트릭으로 과부하 할 수 있습니다. 증인:

struct func {
    operator string() { return "1";}
    operator int() { return 2; }
};

int main( ) {
    int x    = func(); // calls int version
    string y = func(); // calls string version
    double d = func(); // calls int version
    cout << func() << endl; // calls int version
    func(); // calls neither
}

다른 팁

반환 유형에 의해 기능이 과부하 된 경우이 두 개의 과부하가 발생한 경우

int func();
string func();

컴파일러가 이와 같은 전화를 볼 때 전화 할 두 가지 기능 중 어느 것을 파악할 수있는 방법은 없습니다.

void main() 
{
    func();
}

이러한 이유로 언어 디자이너는 종종 반환 가치 과부하를 허용하지 않습니다.

그러나 일부 언어 (예 : MSIL), 하다 반환 유형별로 과부하를 허용합니다. 그들은 물론 위의 어려움에 직면하지만 해결 방법이있어 문서를 참조해야합니다.

그러한 언어로 다음을 어떻게 해결 하시겠습니까?

f(g(x))

만약에 f 과부하가있었습니다 void f(int) 그리고 void f(string) 그리고 g 과부하가있었습니다 int g(int) 그리고 string g(int)? 당신은 어떤 종류의 disambiguator가 필요합니다.

나는 당신이 필요할 수있는 상황이 함수의 새로운 이름을 선택함으로써 더 잘 제공 될 것이라고 생각합니다.

C ++ 특이점을 훔치기 위해 또 다른 매우 유사한 질문에서 답하십시오 (잘 속는 사람?):


StrousTrup (다른 C ++ 아키텍트의 입력으로 가정)이 과부하 분해능이 '컨텍스트 독립적'이기를 원했기 때문에 기능 반환 유형은 과부하 분해능에서 작동하지 않습니다. "C ++ 프로그래밍 언어, 제 3 판"의 7.4.1- "오버로드 및 리턴 유형"을 참조하십시오.

그 이유는 개별 연산자 또는 기능 호출 컨텍스트 독립성에 대한 해상도를 유지하는 것입니다.

그들은 과부하가 어떻게 호출되는지에 기초하여 결과가 사용되는 방식 (전혀 사용 된 경우)을 기반으로하기를 원했습니다. 실제로, 결과를 사용하지 않고 많은 기능이 호출되거나 결과는 더 큰 표현의 일부로 사용됩니다. 그들이 결정했을 때 내가 확신하는 한 가지 요소는 반환 유형이 해상도의 일부라면 복잡한 규칙으로 해결해야 할 또는 컴파일러 던지기를 해야하는 과부하 된 기능에 대한 많은 호출이 있다는 것입니다. 호출이 모호한 오류.

그리고 주님은 C ++ 과부하 분해능이 서있는대로 충분히 복잡합니다 ...

Haskell에서는 기능 과부하가 없더라도 가능합니다. Haskell은 유형 클래스를 사용합니다. 프로그램에서는 다음을 볼 수 있습니다.

class Example a where
    example :: Integer -> a

instance Example Integer where  -- example is now implemented for Integer
    example :: Integer -> Integer
    example i = i * 10

기능 과부하 자체는 그렇게 인기가 없습니다. 내가 본 언어는 대부분 C ++, 아마도 Java 및/또는 C#입니다. 모든 역학 언어에서는 다음과 같은 속기입니다.

define example:i
  ↑i type route:
    Integer = [↑i & 0xff]
    String = [↑i upper]


def example(i):
    if isinstance(i, int):
        return i & 0xff
    elif isinstance(i, str):
        return i.upper()

따라서 그 안에는 많은 점이 없습니다. 대부분의 사람들은 언어가 사용하는 곳마다 한 줄을 삭제하는 데 도움이 될 수 있는지에 관심이 없습니다.

패턴 매칭은 기능 과부하와 다소 비슷하며 때로는 비슷하게 작동한다고 생각합니다. 그것은 거의 프로그램에만 유용하기 때문에 일반적이지 않으며 대부분의 언어로 구현하기가 까다 롭기 때문에 일반적이지 않습니다.

당신은 다음을 포함하여 언어로 구현하기에 더 쉽게 구현하기 쉬운 다른 많은 기능이 있습니다.

  • 동적 타이핑
  • 목록, 사전 및 유니 코드 문자열에 대한 내부 지원
  • 최적화 (JIT, 유형 추론, 컴파일)
  • 통합 배포 도구
  • 도서관 지원
  • 지역 사회 지원 및 수집 장소
  • 풍부한 표준 라이브러리
  • 좋은 구문
  • 평가 인쇄 루프를 읽으십시오
  • 반사 프로그래밍 지원

좋은 대답! A.rex의 답변은 특히 매우 상세하고 유익합니다. 그가 지적했듯이 C ++ 하다 컴파일 할 때 사용자가 제공하는 유형 조정 연산자를 고려하십시오 lhs = func(); (FUNC가 실제로 구조물의 이름 인 곳). 내 해결 방법은 약간 다릅니다. 더 나은 것이 아니라 다릅니다 (동일한 기본 아이디어를 기반으로하지만).

나는 가지고 있었지만 원해 쓰기...

template <typename T> inline T func() { abort(); return T(); }

template <> inline int func()
{ <<special code for int>> }

template <> inline double func()
{ <<special code for double>> }

.. etc, then ..

int x = func(); // ambiguous!
int x = func<int>(); // *also* ambiguous!?  you're just being difficult, g++!

나는 매개 변수화 된 구조물을 사용하는 솔루션으로 끝났다 (t = 반환 유형 포함).

template <typename T>
struct func
{
    operator T()
    { abort(); return T(); } 
};

// explicit specializations for supported types
// (any code that includes this header can add more!)

template <> inline
func<int>::operator int()
{ <<special code for int>> }

template <> inline
func<double>::operator double()
{ <<special code for double>> }

.. etc, then ..

int x = func<int>(); // this is OK!
double d = func<double>(); // also OK :)

이 솔루션의 이점은 이러한 템플릿 정의를 포함하는 모든 코드가 더 많은 유형에 대해 더 많은 전문화를 추가 할 수 있다는 것입니다. 또한 필요에 따라 구조물을 부분 전문화 할 수 있습니다. 예를 들어, 포인터 유형에 대한 특별 처리를 원한다면 :

template <typename T>
struct func<T*>
{
    operator T*()
    { <<special handling for T*>> } 
};

부정적으로, 당신은 글을 쓸 수 없습니다 int x = func(); 내 솔루션으로. 당신은 써야합니다 int x = func<int>();. 유형 변환 연산자를 보면서 컴파일러에게 소송을 요청하는 대신 반환 유형이 무엇인지 명시 적으로 말해야합니다. 나는 "나의"솔루션과 a.rex의 둘 다 파레토-최적의 전선 이 C ++ 딜레마를 다루는 방법 :)

반환 유형이 다른 방법을 과부하하려면 추가하십시오. 기본값을 가진 더미 매개 변수 오버로드 실행을 허용하지만 매개 변수 유형이 다르기 때문에 다음에 과부하 로직이 작동하는 것이 델파이에 있습니다.

type    
    myclass = class
    public
      function Funct1(dummy: string = EmptyStr): String; overload;
      function Funct1(dummy: Integer = -1): Integer; overload;
    end;

이렇게 사용하십시오

procedure tester;
var yourobject : myclass;
  iValue: integer;
  sValue: string;
begin
  yourobject:= myclass.create;
  iValue:= yourobject.Funct1(); //this will call the func with integer result
  sValue:= yourobject.Funct1(); //this will call the func with string result
end;

이미 보여 지듯이 - 반환 유형에 의해서만 다른 함수의 모호한 호출은 모호성을 소개합니다. 모호성은 결함이있는 코드를 유도합니다. 결함이있는 코드를 피해야합니다.

모호한 시도에 의해 주도 된 복잡성은 이것이 좋은 해킹이 아니라는 것을 보여줍니다. 지적 운동 외에도 참조 매개 변수와 함께 절차를 사용하지 않는 이유.

procedure(reference string){};
procedure(reference int){};
string blah;
procedure(blah)

이 과부하 기능은 약간 다른 방식으로 보면 관리하기 어렵지 않습니다. 다음을 고려하세요,

public Integer | String f(int choice){
if(choice==1){
return new string();
}else{
return new Integer();
}}

언어가 오버로드를 반환하면 매개 변수 오버로드를 허용하지만 복제는 아닙니다. 이것은 다음의 문제를 해결할 것입니다.

main (){
f(x)
}

선택할 F (int 선택)가 하나만 있기 때문입니다.

.NET에서는 때때로 하나의 매개 변수를 사용하여 일반적인 결과에서 원하는 출력을 표시 한 다음 전환하여 기대하는 것을 얻습니다.

씨#

public enum FooReturnType{
        IntType,
        StringType,
        WeaType
    }

    class Wea { 
        public override string ToString()
        {
            return "Wea class";
        }
    }

    public static object Foo(FooReturnType type){
        object result = null;
        if (type == FooReturnType.IntType) 
        {
            /*Int related actions*/
            result = 1;
        }
        else if (type == FooReturnType.StringType)
        {
            /*String related actions*/
            result = "Some important text";
        }
        else if (type == FooReturnType.WeaType)
        {
            /*Wea related actions*/
            result = new Wea();
        }
        return result;
    }

    static void Main(string[] args)
    {
        Console.WriteLine("Expecting Int from Foo: " + Foo(FooReturnType.IntType));
        Console.WriteLine("Expecting String from Foo: " + Foo(FooReturnType.StringType));
        Console.WriteLine("Expecting Wea from Foo: " + Foo(FooReturnType.WeaType));
        Console.Read();
    }

어쩌면이 예제도 도움이 될 수 있습니다.

C ++

    #include <iostream>

enum class FooReturnType{ //Only C++11
    IntType,
    StringType,
    WeaType
}_FooReturnType;

class Wea{
public:
    const char* ToString(){
        return "Wea class";
    }
};

void* Foo(FooReturnType type){
    void* result = 0;
    if (type == FooReturnType::IntType) //Only C++11
    {
        /*Int related actions*/
        result = (void*)1;
    }
    else if (type == FooReturnType::StringType) //Only C++11
    {
        /*String related actions*/
        result = (void*)"Some important text";
    }
    else if (type == FooReturnType::WeaType) //Only C++11
    {
        /*Wea related actions*/
        result = (void*)new Wea();
    }
    return result;
}

int main(int argc, char* argv[])
{
    int intReturn = (int)Foo(FooReturnType::IntType);
    const char* stringReturn = (const char*)Foo(FooReturnType::StringType);
    Wea *someWea = static_cast<Wea*>(Foo(FooReturnType::WeaType));
    std::cout << "Expecting Int from Foo: " << intReturn << std::endl;
    std::cout << "Expecting String from Foo: " << stringReturn << std::endl;
    std::cout << "Expecting Wea from Foo: " << someWea->ToString() << std::endl;
    delete someWea; // Don't leak oil!
    return 0;
}

기록을 위해 옥타브 리턴 요소에 따라 스칼라 대 배열에 따라 다른 결과를 허용합니다.

x = min ([1, 3, 0, 2, 0])
   ⇒  x = 0

[x, ix] = min ([1, 3, 0, 2, 0])
   ⇒  x = 0
      ix = 3 (item index)

CF도 단일 가치 분해.

이것은 C ++에 대해 약간 다릅니다. 반환 유형별로 과부하로 간주되는지 모르겠습니다. 그것은 방식으로 작용하는 템플릿 전문화에 가깝습니다.

util.h

#ifndef UTIL_H
#define UTIL_H

#include <string>
#include <sstream>
#include <algorithm>

class util {
public: 
    static int      convertToInt( const std::string& str );
    static unsigned convertToUnsigned( const std::string& str );
    static float    convertToFloat( const std::string& str );
    static double   convertToDouble( const std::string& str );

private:
    util();
    util( const util& c );
    util& operator=( const util& c );

    template<typename T>
    static bool stringToValue( const std::string& str, T* pVal, unsigned numValues );

    template<typename T>
    static T getValue( const std::string& str, std::size_t& remainder );
};

#include "util.inl"

#endif UTIL_H

util.inl

template<typename T>
static bool util::stringToValue( const std::string& str, T* pValue, unsigned numValues ) {
    int numCommas = std::count(str.begin(), str.end(), ',');
    if (numCommas != numValues - 1) {
        return false;
    }

    std::size_t remainder;
    pValue[0] = getValue<T>(str, remainder);

    if (numValues == 1) {
        if (str.size() != remainder) {
            return false;
        }
    }
    else {
        std::size_t offset = remainder;
        if (str.at(offset) != ',') {
            return false;
        }

        unsigned lastIdx = numValues - 1;
        for (unsigned u = 1; u < numValues; ++u) {
            pValue[u] = getValue<T>(str.substr(++offset), remainder);
            offset += remainder;
            if ((u < lastIdx && str.at(offset) != ',') ||
                (u == lastIdx && offset != str.size()))
            {
                return false;
            }
        }
    }
    return true;    
}

util.cpp

#include "util.h"

template<>
int util::getValue( const std::string& str, std::size_t& remainder ) {
    return std::stoi( str, &remainder );
} 

template<>
unsigned util::getValue( const std::string& str, std::size_t& remainder ) {
    return std::stoul( str, &remainder );
}

template<>
float util::getValue( const std::string& str, std::size_t& remainder ) {
    return std::stof( str, &remainder );
}     

template<>   
double util::getValue( const std::string& str, std::size_t& remainder ) {
    return std::stod( str, &remainder );
}

int util::convertToInt( const std::string& str ) {
    int i = 0;
    if ( !stringToValue( str, &i, 1 ) ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to int";
        throw strStream.str();
    }
    return i;
}

unsigned util::convertToUnsigned( const std::string& str ) {
    unsigned u = 0;
    if ( !stringToValue( str, &u, 1 ) ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to unsigned";
        throw strStream.str();
    }
    return u;
}     

float util::convertToFloat(const std::string& str) {
    float f = 0;
    if (!stringToValue(str, &f, 1)) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to float";
        throw strStream.str();
    }
    return f;
}

double util::convertToDouble(const std::string& str) {
    float d = 0;
    if (!stringToValue(str, &d, 1)) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to double";
        throw strStream.str();
    }
    return d;
}

이 예제는 반환 유형별로 기능 과부하 분해능을 정확히 사용하지는 않지만이 C ++ 비 객체 클래스는 템플릿 전문화를 사용하여 개인 정적 메소드로 리턴 유형별로 기능 과부하 해상도를 시뮬레이션합니다.

각각 convertToType 함수는 함수 템플릿을 호출합니다 stringToValue() 이 기능 템플릿의 구현 세부 사항 또는 알고리즘을 보면 호출 중입니다. getValue<T>( param, param ) 그리고 그것은 유형을 되돌리고 있습니다 T 그리고 그것을 a에 저장합니다 T* 그것은 전달됩니다 stringToValue() 함수 템플릿은 매개 변수 중 하나입니다.

이와 같은 것 외에는; C ++에는 실제로 리턴 유형별로 기능 과부하 분해능을 갖는 메커니즘이 없습니다. 내가 알지 못하는 다른 구성이나 메커니즘이있을 수 있습니다.

나는 이것이 현대 C ++ 정의의 차이라고 생각합니다… 왜?

int func();
double func();

// example 1. → defined
int i = func();

// example 2. → defined
double d = func();

// example 3. → NOT defined. error
void main() 
{
    func();
}

C ++ 컴파일러가 예제 "3"에서 오류를 던질 수없는 이유 "1+2"에서 코드를 수락 할 수있는 이유는 무엇입니까?

대부분의 정적 언어는 이제 제네릭을 지원하여 문제를 해결할 수 있습니다. 앞에서 언급했듯이 매개 변수 차이가 없으면 어떤 전화를 호출 해야하는지 알 수있는 방법이 없습니다. 따라서이 작업을 수행하려면 제네릭을 사용하고 하루를 부르십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top