This is an artefact of the history of OpenGL.
For OpenGL versions 1.1 to 1.4, providing a pointer to actual system memory data was the only way to use glDrawElements; the last parameter was interpreted as a pointer to data rather than an offset into a buffer, and the second code sample you give (
gl::glDrawElements(gl::GL_TRIANGLES, IndexBuffer.size(), gl::GL_UNSIGNED_INT, &(IndexBuffer.at(0)));) actually did work.
With OpenGL 1.5 or the GL_ARB_vertex_buffer_object extension this behaviour changed. Now if a non-zero buffer object is bound to GL_ELEMENT_ARRAY_BUFFER the pointer is re-interpreted as an offset into the buffer. I recommend reading the "Issues" section of the extension specification as it often gives insight into the reasons why certain decisions which may seem odd today actually made some degree of sense at the time they were originally made. For now it will suffice to quote:
The standard GL pointer APIs have been overloaded to be able to refer to offsets within these buffers, rather than adding new entry points ..... It is easily and cleanly added with just the addition of a binding point for the index buffer object. Since our approach of overloading pointers works for any pointer in GL, no additional APIs need be defined...
In modern OpenGL this behaviour changed again. Because it was no longer legal to source vertex or index data from system memory pointers, the only variant that may be used is the overloaded variant, where the parameter is still a pointer but is reinterpreted as an offset.
So hopefully you'll see that what looks like a very odd API today was actually originally designed as something quite different but because of the way the API evolved it too evolved into what it is today.