Skip to content

Instantly share code, notes, and snippets.

@killwing
Created February 6, 2013 08:29
Show Gist options
  • Save killwing/4721169 to your computer and use it in GitHub Desktop.
Save killwing/4721169 to your computer and use it in GitHub Desktop.
[Expected] Make exceptions be the error codes! from @andrei
#ifndef EXPECTED_H
#define EXPECTED_H
#include <exception>
#include <typeinfo>
// Make exceptions be the error codes!
template <typename T>
class Expected {
public:
Expected(const T& rhs) : ham(rhs), gotHam(true) {}
Expected(T&& rhs) : ham(std::move(rhs)), gotHam(true) {}
Expected(const Expected& rhs) : gotHam(rhs.gotHam) {
if (gotHam) {
new(&ham) T(rhs.ham);
} else {
new(&spam) std::exception_ptr(rhs.spam);
}
}
Expected(Expected&& rhs) : gotHam(rhs.gotHam) {
if (gotHam) {
new(&ham) T(std::move(rhs.ham));
} else {
new(&spam) std::exception_ptr(std::move(rhs.spam));
}
}
~Expected() {}
void swap(Expected& rhs) {
if (gotHam) {
if (rhs.gotHam) {
using std::swap;
swap(ham, rhs.ham);
} else {
auto t = std::move(rhs.spam);
new(&rhs.ham) T(std::move(ham));
new(&spam) std::exception_ptr(t);
std::swap(gotHam, rhs.gotHam);
}
} else {
if (rhs.gotHam) {
rhs.swap(*this);
} else {
spam.swap(rhs.spam);
std::swap(gotHam, rhs.gotHam);
}
}
}
// Building from exception
template <typename E>
static Expected<T> fromException(const E& exception) {
if (typeid(exception) != typeid(E)) {
throw std::invalid_argument("slicing detected");
}
return fromException(std::make_exception_ptr(exception));
}
static Expected<T> fromException(std::exception_ptr p) {
Expected<T> result;
result.gotHam = false;
new(&result.spam) std::exception_ptr(std::move(p));
return result;
}
static Expected<T> fromException() {
return fromException(std::current_exception());
}
// Access
bool valid() const {
return gotHam;
}
T& get() {
if (!gotHam) {
std::rethrow_exception(spam);
}
return ham;
}
const T& get() const {
if (!gotHam) {
std::rethrow_exception(spam);
}
return ham;
}
// Probing for Type
template <typename E>
bool hasException() const {
try {
if (!gotHam) {
std::rethrow_exception(spam);
}
} catch (const E& object) {
return true;
} catch (...) {
}
return false;
}
// Icing
template <typename F>
static Expected fromCode(F fun) {
try {
return Expected(fun());
} catch (...) {
return fromException();
}
}
private:
Expected() {} // used internally
union {
T ham;
std::exception_ptr spam;
};
bool gotHam;
};
#endif // EXPECTED_H
#include <iostream>
#include <string>
#include <stdexcept>
#include <sstream>
#include "Expected.h"
using namespace std;
Expected<int> parseInt(const std::string& s) {
int result = 0;
for (auto& i : s) {
if (i < 48 || i > 57) {
return Expected<int>::fromException(std::invalid_argument("not a number"));
}
}
if (s.size() > 10) {
return Expected<int>::fromException(std::out_of_range("overflow"));
}
istringstream i(s);
i >> result;
return result;
}
int main() {
string s;
cin >> s;
//auto x = parseInt(s).get(); // throw on error
auto y = parseInt(s); // won't throw
if (!y.valid()) {
// handle locally
if (y.hasException<std::invalid_argument>()) {
cout << "no digits" << endl;
}
y.get(); // just "re"throw
} else {
cout << "parse ok: " << y.get() << endl;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment