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


当前回答

如前所述,对仅因返回类型不同而不同的函数的模糊调用会引入模糊。 模糊性会导致有缺陷的代码。 必须避免有缺陷的代码。

试图模糊化所带来的复杂性表明这不是一个好的hack。 除了智力练习之外,为什么不使用带有引用参数的过程呢?

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

其他回答

如果你想重载具有不同返回类型的方法,只需添加一个具有默认值的虚拟参数来允许重载执行,但不要忘记参数类型应该是不同的,因此重载逻辑工作接下来是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;

如前所述,对仅因返回类型不同而不同的函数的模糊调用会引入模糊。 模糊性会导致有缺陷的代码。 必须避免有缺陷的代码。

试图模糊化所带来的复杂性表明这不是一个好的hack。 除了智力练习之外,为什么不使用带有引用参数的过程呢?

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

我认为这是现代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”中的代码??

在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()

因此没有什么意义。大多数人不感兴趣的是语言是否能帮助你在使用它的时候省去一行字。

模式匹配有点类似于函数重载,我想有时工作方式也类似。但它并不常见,因为它只对少数程序有用,而且在大多数语言上实现起来很棘手。

你可以看到,在语言中还有无限多更好更容易实现的特性,包括:

动态类型 内部支持列表,字典和unicode字符串 优化(JIT、类型推断、编译) 集成部署工具 库支持 社区支持和聚集场所 丰富的标准库 好的语法 读取eval打印循环 对反射编程的支持

这一点在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++并没有通过返回类型来实现函数重载解析的机制。可能还有我不知道的其他构造或机制可以通过返回类型模拟解析。