This was an engineering tradeoff / judgement made on my part. On the one hand we could partition up the mutex types as finely as possible: does / doesn't have timed operations, does / doesn't support shared locking, does / doesn't support upgrade locking (note shared_mutex was designed within the context of upgrade_mutex although upgrade_mutex was not accepted). This would make for 4 new mutex types. Recursion would be yet another way to partition up the functionality.
On the other hand we could just build in the way proposed (half-accepted): add two new mutex types: shared_mutex and upgrade_mutex.
I chose the latter with the rationale that:
1. The timed shared / unique locking are arguably desired functionality as indicated by the inclusion of these operations in the POSIX standard.
2. I felt that shared locking in general is functionality that needed to be in C++, and proposing two new mutexes (shared and upgrade) was already pushing the practical limits of getting this proposal accepted. Proposing 4 new mutexes would be far riskier.
3. I had demonstrated a very reasonable implementation that is 100% portable, built on top of std::mutex and std::condition_variable (and supports the timed operations with no extra expense). Although the implementation doesn't show it, I kept the mutex state in a single word so that one could optimize the operations (i.e. fast path) with atomics.
4. I've been asked previous questions along the lines of: Why doesn't the shared_mutex support feature X? One example of X is reader/writer priority. And I had one person make a very good argument to me why he needed it, complete with his implementation of it. I noted though that his acme::shared_mutex was exactly the right solution for his application. And it would interoperate seamlessly with the rest of the std-defined mutex/lock environment.
I.e. std::unique_lock<acme::shared_mutex> worked perfectly. As does std::shared_lock<acme::shared_mutex>. Custom mutexes, if they adhere to the mutex requirements, just work.
So additionally, modulo a minor wording defect that you have brought to my attention, the mutexes you mention could be supplied by a 3rd party, and can work with unique_lock / shared_lock at el. perfectly, as long as the client doesn't use the timed operations. Just as you can put a non-DefaultConstructible type into a std::vector, unless you use one of the members that requires DefaultConstructible, the lock types happily just work when their Mutex meets a subset of the requirements.
The note in [thread.lock.shared]:
[Note: shared_lock<Mutex> meets the TimedLockable requirements (30.2.5.4). — end note]
is an overstatement. Each member of the shared_lock states the requirements on Mutex in terms of its Effects clause. E.g:
void lock();
Effects: pm->lock_shared().
I.e. the Mutex must support lock_shared(). That's it.
Should these shared_mutexes-without-timed-operations become prevalent in the future, there is nothing stopping the committee from standardizing them too. And they will just work in the existing mutex/lock ecosystem.
Howard