So it turns out I have misunderstood what k-fold CV actually does. I had originally thought that (e.g.) 5-fold CV splits the whole dataset into 5 subsets, then on each iteration the model is trained with 4 and tested with the held-out subset.
But various documentation (https://scikit-learn.org/stable/modules/cross_validation.html) says an additional subset is left out of this procedure, and that the model is trained, validated, and tested? So why is testing the model using the held-out subsets alone not sufficient?
And how does this overcome the problems associated with just using train_test_split, given that you still have to define a subset of the data for testing the final model?