The Forkless Philosopher

Result Types

void vs. bool vs. integer vs. class

What is a good return value for a method? Think of a method that deletes a license-plate number from a database: void deleteFromDatabase(string lpn) { [...] } How will you know if the operation was successful? Perhaps connecting to the database failed? Then the license-plate number will still be in the database while you (or your code's logic) assumes it is not. void is definitely not a good return value.

Quite common is boolean deleteFromDatabase(string lpn) { [...] }, with the convention that true means that the operation succeeded, whereas false indicates failure. This is better.
However, this is rarely expressed with an explicit boolean return type; instead, int is used, relying on the implicit conversion of integers into bools that the C++ standard provides. The definition of which integers constitute false and which true can be found on page 71 of The C++ Programming Language (3rd edition) by Bjarne Stroustrup (Addison-Wesley, 2002): "nonzero integers convert to true and 0 converts to false".
This allows constructs like if (deleteFromDatabase("S12345F")) { [...] } which is completely legal code, although perhaps not the most legible one. To prevent the usage of such constructs, some people revert the logic so that 0 indicates success and all other values indicate an error.

Another reason to revert the logic so that 0 indicates success might be to mimic the behaviour of shell commands.

The third reason is more practical in nature. If you use 0 to indicate failure and all other integers to indicate success, all you can do is report the fact that the function call failed, but not the reason. But what if Fred from the other department calls and says: "I need to know why the operation failed. With some failures, I can eliminate the cause and try again". Which is a legitimate and sensible request, since it will make the software more robust.
This is the main reason to use a sort of logic where 0 indicates success and all other integers indicate failure - you then have the capability of communicating what exactly went wrong.
You can now also use an enumeration to use plain english instead of cryptic error codes: EDBServerUnreachable is so much more descriptive than, say, -1.

But if you are willing to create your own return type anyway, why not go for a class (don't use a struct; with a class you can supply some methods like equals() that might be useful in unit tests)? CDBOpResult deleteFromDatabase(string lpn) { [...] } does not only leave no room for ambiguity in the interpretation of the result (i.e. it is type safe), it offers you flexibility as well (e.g.: CDBOpResult::getErrorMessage()).
And be sure to hide the implementation details - don't use static attributes to communicate results: public static int CDBOpResult::Success = 0; might lead developers to rely on the implementation detail that CDBOpResult::Success equals 0. Instead, provide methods like bool CDBOpResult::opSucceeded() and bool CDBOpResult::opFailedNoConnection() to communicate the result of the operation.