268 Stimmen

Funktionsüberladung nach Rückgabetyp?

Warum unterstützen nicht mehr gängige statisch typisierte Sprachen das Überladen von Funktionen/Methoden nach Rückgabetyp? Ich kann mich an keine erinnern, die das tut. Es scheint nicht weniger nützlich oder sinnvoll zu sein als die Unterstützung von Überladung nach Parametertyp. Wie kommt es, dass es so viel weniger populär ist?

2 Stimmen

0 Stimmen

@user195488 dies ist kein Duplikat, weil es eine allgemeine Frage ist.

0voto

Francis Cugler Punkte 7624

Dies ist etwas anders für C++; ich weiß nicht, ob es als Überladen durch Rückgabetyp direkt betrachtet werden würde. Es handelt sich eher um eine Template-Spezialisierung, die in der Art von.

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

In diesem Beispiel wird nicht genau die Auflösung von Funktionsüberladungen nach Rückgabetyp verwendet, aber diese C++-Nichtobjektklasse verwendet die Vorlagenspezialisierung, um die Auflösung von Funktionsüberladungen nach Rückgabetyp mit einer privaten statischen Methode zu simulieren.

Jeder der convertToType Funktionen rufen die Funktionsvorlage stringToValue() und wenn Sie sich die Implementierungsdetails oder den Algorithmus dieser Funktionsvorlage ansehen, ruft sie getValue<T>( param, param ) und es gibt einen Typ zurück T und Speicherung in einer T* die in die Datei stringToValue() Funktionsvorlage als einen ihrer Parameter.

Abgesehen von so etwas hat C++ nicht wirklich einen Mechanismus, um die Auflösung von Funktionsüberladungen nach Rückgabetyp zu ermöglichen. Möglicherweise gibt es andere Konstrukte oder Mechanismen, die mir nicht bekannt sind, die eine Auflösung nach Rückgabetyp simulieren könnten.

-1voto

Andreas Otto Punkte 181

Ich denke, dies ist eine Lücke in der modernen C++ Definition warum?

int func();
double func();

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

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

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

Warum kann ein C++-Compiler im Beispiel "3" keinen Fehler auslösen und den Code in Beispiel "1+2" akzeptieren?

0 Stimmen

Ja, das ist es, was sie zu der Zeit für C# (und vielleicht C++) in Betracht gezogen haben. Aber während Ihr Code trivial ist, wird es, sobald Sie Klassenhierarchien, virtuelle Methoden, abstrakte Methoden und Schnittstellen, andere Überladungen und manchmal Mehrfachvererbung hinzufügen, sehr schnell sehr komplex zu entscheiden, welche Methode aufgelöst werden soll. Es ist eine Entscheidung der Designer, diesen Weg nicht zu gehen, aber andere Sprachen haben sich auf verschiedenen Ebenen des Erfolgs anders entschieden.

-2voto

Charles Graham Punkte 23517

Die meisten statischen Sprachen unterstützen jetzt auch Generika, was Ihr Problem lösen würde. Wie bereits erwähnt, gibt es ohne Parameterdiffs keine Möglichkeit zu wissen, welche man aufrufen muss. Wenn Sie dies also tun möchten, verwenden Sie einfach Generika und lassen Sie es gut sein.

0 Stimmen

Das ist nicht dasselbe. Wie würden Sie eine Funktion handhaben, die die Eingabe in einen Integer, Float, Bool oder was auch immer übersetzt, je nachdem, wie der Rückgabetyp verwendet wird? Das kann nicht verallgemeinert werden, da man für jeden Typ einen eigenen Fall braucht.

0 Stimmen

Siehe codeproject.com/KB/cpp/returnoverload.aspx für eine clevere Strategie zum "Überladen nach Rückgabetyp". Anstatt eine Funktion func() zu definieren, definieren Sie eine Struktur func, geben ihr einen Operator()() und Konvertierungen in jeden geeigneten Typ.

0 Stimmen

Jay, Sie definieren den Rückgabetyp, wenn Sie die Funktion aufrufen. Wenn die Eingänge unterschiedlich sind, gibt es überhaupt kein Problem. Wenn es die gleichen sind, können Sie eine generische Version, die einige Logik auf der Grundlage des Typs mit GetType() haben kann.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X