Any identifier with two underscores is reserved for the implementation. Using such an identifier yields undefined behaviour. Change your include guard. Something along QUICKSORT_GAMDSCHIEE_H is perfectly fine.
The user interface of quicksort should only take a std::vector. That way one cannot use size() by accident:
void quicksort(std::vector<int> & v) {
quicksort_impl(v, 0, v.size() - 1);
}
Make it hard to use your code in a wrong way.
You can return immediately in both partition and quicksort if ileft == iright and spare yourself some other if.
I think instead of having swap.cpp I could've simply used std::swap, right?
Exactly, or at least re-use it:
void swap(std::vector<int> & v, int i, int j) {
std::swap(v[i], v[j]);
}
Instead of int we should use std::vector<int>::size_type (which will be size_t usually).
There's no reason to limit your quicksort to std::vector<int> it works fine for any std::vector<T> as long as T provides operator<.
To your "faster quicksort algorithm" question: you can find a std::vector where quicksort will take \$\mathcal O(n^2)\$ instead of \$\mathcal O(n \log n)\$. It's average time complexity is \$\mathcal O(n \log n)\$. Mergesort on the other hand is always \$\mathcal \Theta(n \log n)\$ time complexity.
Usually std::sort will be fast enough for all your use cases.