为什么主流的静态类型语言不支持按返回类型重载函数/方法?我想不出有什么能做到。这似乎并不比支持按参数类型重载更有用或更合理。为什么它不那么受欢迎呢?


当前回答

我认为这是现代c++定义中的一个GAP……为什么?

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”中的代码??

其他回答

如果你想重载具有不同返回类型的方法,只需添加一个具有默认值的虚拟参数来允许重载执行,但不要忘记参数类型应该是不同的,因此重载逻辑工作接下来是delphi上的示例:

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;

大多数静态语言现在也支持泛型,这将解决您的问题。如前所述,如果没有参数差异,就无法知道调用哪一个。如果你想这样做,使用泛型就可以了。

如果函数被返回类型重载并且有这两个重载

int func();
string func();

在看到这样的调用时,编译器无法确定调用这两个函数中的哪一个

void main() 
{
    func();
}

由于这个原因,语言设计者通常不允许返回值重载。

然而,有些语言(如MSIL)允许按返回类型重载。当然,它们也面临上述困难,但它们有变通办法,为此您必须查阅它们的文档。

我认为这是现代c++定义中的一个GAP……为什么?

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”中的代码??

这一点在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并将其存储到T*中,T*作为其参数之一传递到stringToValue()函数模板。

除了这样的东西;c++并没有通过返回类型来实现函数重载解析的机制。可能还有我不知道的其他构造或机制可以通过返回类型模拟解析。