What post conditions apply to f after std::move(f) has been executed?
This can largely be dictated by the author of foo, but also constrained by the algorithms (std or not) that place requirements on foo.
Many algorithms will require that in its moved-from state foo be Destructible and can be assigned a new value. But this depends on the context in which foo will be used.
If foo is used with a std-library component, then the requirements are dictated by Table 20 -- MoveConstructible requirements:
rv’s state is unspecified [ Note:rv must still meet the requirements
of the library compo- nent that is using it. The operations listed in
those requirements must work as specified whether rv has been moved
from or not. — end note ]
For example: Let's say you call std::sort with a vector<foo>. std::sort will require of foo: Swappable, MoveConstructible, Destructible, MoveAssignable, and LessThanComparable.
std::sort places these requirements on foo whether or not foo is in a moved-from state.
Strictly speaking one should not need to have foo be LessThanComparable when in a moved-from state if using with std::sort. It would be pointless for an implementor to compare a moved-from object since its value is unspecified. Nevertheless, the C++11 and C++14 standards currently require LessThanComparable. The result need not be sensible, but it is required to not crash if executed. A future standard might relax this requirement, but who knows.
So in summary, the author of foo can state what operations are allowed on a moved-from foo.
And any algorithm can state what it requires of the types it operates on.
In the intersection where foo meets the requirements of an algorithm, code works. The C++ standard does not consider a moved-from state special.