Question

The following code snippet is of a game, the compiler is complaining about the return values so I would like some feedback on how to otherwise do this trick to let a function return two different types based on the type put in but without overloading

template <typename T>
T GetTimeDead(uint64 Guid)
{
    bool stringOutput;
    if(typeid(T) == typeid(float))
        stringOutput = false;
    else
        stringOutput = true;

    bool found = false;
    for(map<uint32, TrackInfo>::iterator itr = dieTracker.begin(); itr != dieTracker.end(); ++itr)
    {
        if(itr->second.GUID == Guid)
        {
            found = true;
            break;
        }
    }

    if(!found)
        stringOutput ? return "never" : return sObjectMgr->FindCreature(Guid)->GetCreatureData()->spawntimesecs;

    if(!stringOutput)
        return dieTracker.find(Guid)->second.seconds;
    float seconds = dieTracker.find(Guid)->second.seconds;
    uint64 secs    = seconds % 60;
    uint64 minutes = seconds % 3600 / 60;
    uint64 hours   = seconds % 86400  / 3600;
    uint64 days    = seconds / 86400;
    ostringstream ss;
    if(days)
        days != 1 ? ss << days << " Days " : ss << days << " Day ";
    if(hours)
        hours != 1 ? ss << hours << " Hours" : ss << hours << " Hour";
    if(minutes)
        minutes != 1 ? ss << minutes << " Minutes " : ss << minutes << " Minutes ";
    if(secs || (!days && !hours && !minutes))
        secs != 1 ? ss << secs << " Seconds " : ss << secs << " Second ";
    ss << "ago";
    return ss.str();
}
Was it helpful?

Solution

If you want to define generic behaviour with a template, but override that behaviour for a handful of specific types, you should use a template specialisation.

template<typename T>
std::string GetTimeDead(uint64 Guid)
{ /* code to implement your version that returns std::string */
}

template<>
float GetTimeDead<float>(uint64 Guid)
{ /* code to implement your version that returns float */
}

The reason for your error at the moment is that you have defined the return type to be T. But your logic is set up so that if T is of type float the function tries to return a std::string. There is likely no implicit cast from std::string to T, hence the error.

If you don't want to repeat common code, you could pull that out into a separate template function which is called by the two above.

OTHER TIPS

C++ is a strong and statically typed compiled language - you cannot have a function that returns different types. You are limited to a single return type.

That being said, you can use Boost's variant or Qt's QVariant, which can encapsulate different types. Or implement a custom variant solution tailored to your specific needs.

Regarding the error error C2059: syntax error : 'return', this is the way to fix this specific error:

return stringOutput ? "never" : sObjectMgr->FindCreature(Guid)->GetCreatureData()->spawntimesecs;

the ?: operator is an expression, and each argument of the operator should be an expression. return is a statement. not an expression.

As an expression, ?: has exactly single type. but "never" and spawntimesecs are unrelated types. The compiler cannot handle that. these two values does not belong in the same ?: expression.

You can probably use a union, but it is not recommended.

A better solution will not use template at all, since you do not use the type parameter in any polymorphic way:

float GetTimeDeadFloat(uint64 Guid)
{
    return find(Guid)
           ? dieTracker.find(Guid)->second.seconds
           : sObjectMgr->FindCreature(Guid)->GetCreatureData()->spawntimesecs;
}

string GetTimeDeadString(uint64 Guid)
{
    return find(Guid)
           ? timeToString(dieTracker.find(Guid)->second.seconds)
           : "never";
}


bool find(uint64 Guid) {
    for(map<uint32, TrackInfo>::iterator itr = dieTracker.begin(); itr != dieTracker.end(); ++itr) {
        if(itr->second.GUID == Guid)
            return true;
    }
    return false;
}

string timeToString(float seconds) {
    string res = timeToString(seconds % 3600 / 60, "Minutes");
    res += timeToString(seconds % 86400  / 3600, "Hour");
    res += timeToString(seconds / 86400, "Day");
    if (secs || res.length() == 0)
        res += numToString(seconds % 60, "Second");
    res += "ago";
    return res;
}


string numToString(uint64 num, string type) {
    ostringstream ss;
    if (num)
        ss << num << " " << type << (num != 1) ? "s" : "" << " ";
    return ss.str();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top