The problem is that the specialization causes the compiler to generate actual code, just like an ordinary non-template function. Thus, when you include this in multiple source files you get multiple definitions of that function. In contrast, a function template that is not fully specialized generates no code until it's instantiated.
One way to fix the problem is to mark the specialization inline; this causes it to have internal linkage and so the linker won't complain about it being multiply defined.
The other way would be to have only a prototype of the specialization in the header file, and leave its definition in a source file - again, just like an ordinary, non-template function.
I get the feeling that it has something to do with the fact that I'm specializing over a type that is parameterized itself
I'm not quite sure what you mean - that the Vector3f type is itself an instantiation of a template? If so, there should be no need for special treatment, as it should function just like any other type.
However, if you would like to write a function template that can take a Vector of any dimension, you can do that as well, using what is called a "template template parameter", where the argument to a template is itself a template:
template <int n, template<int> typename V>
void myFunc(const V<n>& v)