Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


how to return different types?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
7 replies to this topic

#1 nuclear123   Members   -  Reputation: 119

Like
0Likes
Like

Posted 23 February 2012 - 08:05 PM

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

}

Sponsor:

#2 zacaj   Members   -  Reputation: 643

Like
0Likes
Like

Posted 23 February 2012 - 08:19 PM

You probably want to switch to inherited classes. Either way, you're going to need to return a pointer instead of the struct itself. First, you'll probably want some way to tell which one is returned, so you should add an integer called type or something first in your structs. Then, make a third struct, called simply XMLReturn or something, that contains only the type variable. Have your function return a pointer of that type, and then just, return whichever struct you allocate normally. You can read the type of your XMLReturn variable and decide what to cast it back to.

#3 zacaj   Members   -  Reputation: 643

Like
-1Likes
Like

Posted 23 February 2012 - 08:24 PM

struct typea
int type
String something

Struct typeb
int type
float somenumber

Struct basetype
int type

basetype* function
if something
typea *ret=malloc(typea) ;
ret.type=1
return ret


basetype *xml=function ()
if xml.type=1
typea *a=(typea*) xml

#4 Trienco   Crossbones+   -  Reputation: 2215

Like
-1Likes
Like

Posted 23 February 2012 - 11:43 PM

That looks incredibly messy and like the equivalent of constantly abusing dynamic_casts in C++ to check types. It seems like conceptual nonsense to be "deriving" unrelated things like Person and Errors from one base and introduce the mess of dynamically allocating/deallocating objects (especially after all the wild brute force casting) to implement the misguided idea of a single function returning completely different types of objects. Sometimes the question isn't "how can I do this", but "why on earth would I WANT to do this".

Either do what tons of C libraries do and have functions always return an error code while using an output parameter for your data, which will look like this

Person person;
Error error = parseXML(xml, &person);


or return a (well defined) dummy Person on error and set a global error object (C typically does both, with functions returning -1 on error and additionally setting the global error number, a completely separate function will then map error codes to error strings). Of course a global error has other problems of its own (not thread safe, the next call might overwrite your previous error, etc.)

In C++ you could use exceptions for errors, which makes some things very convenient (if your calls go through several levels, you don't have a dozen places to do error checking), but also a little messy (you need to learn writing exception safe code and all the try/catch can go a little out of hand).
f@dzhttp://festini.device-zero.de

#5 nuclear123   Members   -  Reputation: 119

Like
0Likes
Like

Posted 24 February 2012 - 12:17 AM

This is all im trying to do:
1.) Have a function that can detect and effectively parse 2 diffrent possible XML messages. Upon return the XML we be stored in the appropriate struct and returned by the function. I can then have the caller somehow know the type that was returned and handle the struct according to its type. Here is my code if this helps


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


#6 Waterlimon   Crossbones+   -  Reputation: 2601

Like
0Likes
Like

Posted 24 February 2012 - 03:27 AM

Make a function to get the type of the data and then call geterror or getplayer, whichever is the right one, passing them the xml already parsed by the gettype thing hopefully (figure out better names for them)


o3o


#7 NightCreature83   Crossbones+   -  Reputation: 2936

Like
0Likes
Like

Posted 24 February 2012 - 03:30 AM

What you are after is a factory pattern and most of those in C++ require RTTI in some way or other. I use class registrars to collect the creation functions at compile time to create objects from a factory http://code.google.c...sRegistration.h, http://code.google.com/p/dxengine/source/browse/trunk/src/RTTI.h, http://code.google.com/p/dxengine/source/browse/trunk/src/RTTIMacros.inl. But I think you can do this with a templated factory as well http://stackoverflow...ry-pattern-in-c
Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, Mad Max

#8 rip-off   Moderators   -  Reputation: 8532

Like
0Likes
Like

Posted 24 February 2012 - 03:33 AM

One idea is to return a tuple of optional Person, Error:
template<typename T>
struct ParseResult {
    boost::optional<T> success;
    boost::optional<Error> error;

    ParseResult(const T &success) {
        // ...
    }

    ParseResult(const Error &error) {
        // ...
    }
};
The caller can inspect the optional values to determine which value was returned. A more generalised version of this is boost::variant, or in extreme cases boost::any. I'm not aware of these types being included in C++0x.

If the file contains many objects, the above could be two containers:

template<typename T>
struct ParseResults {
    std::vector<T> successes;
    std::vector<Error> errors;
};
If the order is important (e.g. parsing a list of elements and you want to correlate errors with particular entries) then you can store the index in the vectors too.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS