Multiple return types?



  • does anyone have any recommendations or advice on how i would do the following. Pretty much i want a function to possibly return 2 different types of structs depending on the XML it is parsing

    @
    struct Error
    {
    string errorMessage;
    string otherinfo;

    }

    struct Person
    {
    string firstname;
    string lastname;
    int age;
    float height;
    }

    Error/Person ParseXML(string XML)
    {
    if (<person>)
    return parsePerson(XML); // return a Error object
    else
    return parseError(XML); // return a person object

    }
    @

    [EDIT: code formatting, please wrap in @-tags, Volker]



  • Below is an example of my code if needed to show exactly what im trying
    @QList<CError> ParseError(QXmlStreamReader& streamReader)
    {
    QList<CError> errorList;
    CError errorBuffer;

    streamReader.readNext();
    while (!(streamReader.tokenType() == QXmlStreamReader::EndElement && streamReader.name() == "ErrorMessage")) {
    if (streamReader.tokenType() == QXmlStreamReader::StartElement) {
    if (streamReader.name() == "Title") {
    errorBuffer.strTitle = streamReader.readElementText();
    }
    if (streamReader.name() == "Message") {
    errorBuffer.strMessage = streamReader.readElementText();
    }
    }
    streamReader.readNext();
    }
    errorList.append(errorBuffer);
    return errorList;
    }

    QList<CSubscription> ParseSubscription(QXmlStreamReader& streamReader)
    {
    QList<CSubscription> subscriptionList;
    CSubscription subscriptionBuffer;

    streamReader.readNext();
    while (streamReader.tokenType() != QXmlStreamReader::EndDocument) {
    while (!(streamReader.tokenType() == QXmlStreamReader::EndElement && streamReader.name() == "Subscription")) {
    if (streamReader.tokenType() == QXmlStreamReader::StartElement) {
    if (streamReader.name() == "NewestVersion") {
    subscriptionBuffer.strNewestVersion = streamReader.readElementText();
    }
    if (streamReader.name() == "ProductName") {
    subscriptionBuffer.strGame = streamReader.readElementText();
    }
    if (streamReader.name() == "ExpiryDate") {
    subscriptionBuffer.strExpireDate = streamReader.readElementText();
    }
    if (streamReader.name() == "Detection") {
    subscriptionBuffer.strDetection = streamReader.readElementText();
    }
    }
    streamReader.readNext();
    }
    subscriptionList.append(subscriptionBuffer);
    }
    return subscriptionList;
    }

    QList<EITHERSTRUCT> ParseXML(QString& strXML)
    {
    QXmlStreamReader streamReader(strXML);

    while (!streamReader.atEnd()) {
    QXmlStreamReader::TokenType token = streamReader.readNext();
    if(token == QXmlStreamReader::StartDocument) {
    continue;
    }
    if(token == QXmlStreamReader::StartElement) {
    if (streamReader.name() == "ErrorMessage") {
    return ParseError(streamReader);
    }
    if (streamReader.name() == "Subscription") {
    return ParseSubscription(streamReader);
    }
    }
    }
    return SOME_ERROR;
    }@



  • Well, you could return a QVariant, either containing an Error or Person struct, but for the sake of a good design I would not recommend doing so.

    A better option would be either adding isValid() to Person and/or adding hasError() / error() to the object enclosing ParseXML(). There are various other options, each better than an union return type.



  • I don't think you can return two different types of objects, in the sense that a function cannot be overloaded with another one which differs only by the return type. What you could do is to use polymorphism: if Person and Error inherit from the same base structure. Then your function should return a pointer on the base class, but on the other hand you should perform some casting to handle properly the returned element. You could of course return a status code (or error code) on top of your structure, which would help to handle the returned structure.



  • No, it is not possible. At compile time you need to decide which return type you need - you have to assign to the correct variable type.

    In use cases like yours, I usually create a return value object, consisting of a bool flag indicating an error or not, am error message and the expected return type. In case of an error, the error message is set, in case everything is ok the return type is filled in.

    @
    // Pseudo code

    class Person {
    string firstname;
    string lastname;
    int age;
    float height;
    };

    class PersonParseReturnVale {
    bool ok;
    string errormessage;
    Person *person;
    };

    PersonParseReturnVale ParseXML(string XML)
    {
    PersonParseReturnVale rv;
    if(parse_is_ok) {
    rv.ok = true;
    rv.person = new Person;
    rv.person.firstname = "bla";+
    } else {
    rv.ok = false;
    rv.errormessage = "Parse Errro";
    }
    return rv;
    }
    @



  • You can always return a
    @ std::pair < Person, Error > @

    or a pair of pointers.
    An alternative, quite evil but fun way would be:
    @
    template < typename RetVal >
    struct ReturnType {
    bool error;
    union {
    RetVal * retval;
    Error * error;
    };
    };

    ReturnValue < Person > ParseXML(string XML) ...
    @


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.