It certainly seems possible if you avoid pointer to functions (and deem them unsafe) by using the ABT of the program. Clang's AST is (despite its name) such an ABT: you will see both declarations and definitions of the functions. By doing your work one definition at a time, you will already have a good baseline.
On the other hand, I wonder whether this is practical. See, the problem is that any function performing a memory allocation is (voluntarily) marked as potentially throwing (because new
never returns null, but throws bad_alloc
instead). Therefore, your noexcept
will be limited to a handful of functions in most cases.
And of course there are all the dynamic conditions like @GManNickG exposed, for example:
void foo(boost::optional<T> const t&) {
if (not t) { return; }
t->bar();
}
Even if T::bar
is noexcept
, dereferencing an optional<T>
may throw (if there is nothing). Of course, this ignores the fact that we already ruled this out (here).
Without having clear conditions on when a function might throw
, static
analysis might prove... useless. The language idioms are designed with exceptions in mind.
Note: as a digression, the optional class could be rewritten so as not to exposed dereferencing, and thus be noexcept
(if the callbacks are):
template <typename T>
class maybe {
public:
template <typename OnNone, typename OnJust>
void act(OnNone&& n, OnJust&& j) noexcept(noexcept(n()) and
noexcept(j(std::declval<T&>())))
{
if (not _assigned) { n(); return; }
j(*reinterpret_cast<T*>(&_storage));
}
private:
std::aligned_storage<sizeof(T), alignof(T)>::type _storage;
bool _assigned;
};
// No idea if this way of expressing the noexcept dependency is actually correct.