Binary search feedback and improvements
You don't need to floor the result of an integer division: the result is exactly the same without it.

When getting the mid value, this is safer:

mid = lo + (hi - lo) / 2;


This way you'll be safe from integer overflows, which can happen when adding two very large integers. (Or long, you get the point)

As you notice, there is some redundancy in the logic of seeing the mid before the main while loop and then again inside the loop, and also in the conditions within the loop and after it. Probably you can refactor this without redundancies, with most logic inside the loop, and almost nothing outside. There should be a return statement inside the loop when the element is found. The empty check will become unnecessary, as the loop condition will never be true for empty input.

template&lt;class T&gt;
long binary_search(const std::vector&lt;T&gt;&amp; v, const T&amp; key){
    long lo = 0;
    long hi = v.size();

    while (lo &lt; hi) {
        long mid = lo + (hi - lo ) / 2; 

        if (v[mid] == key) {
            return mid;
        }
        if (v[mid] &lt; key) {
            lo = mid + 1; 
        } else {
            hi = mid - 1; 
        }
    }

    return -1; 
}