Zum Thema Definitionen in Header Dateien:
Das Inline wird in der einfachen Variante vom Compiler erledigt. Kennt der Compiler die Funktion, sowie die Situation vor und nach dem Aufruf, kann er den Rumpf passend dort einsetzen. Da aber unabhängig voneinander compiliert wird, muss die Funktion in der Quellcodedatei (bzw. über einen Header eingebunden werden), in dem der Funktionsaufruf auch steht. Das verpflichtende inline im Header sagt dem Compiler eigentlich nur das er diese Funktion unter keinen Umständen exportieren soll, da es sonst beim Linken zu Konflikten kommt.
Nehmen wir jetzt den Fall das man zwei Quellcodedateien hat, A mit dem Funktionsaufruf und B mit der Funktion. Dann kriegt der Linker nun die beiden Objektfiles vom Compiler mit dem fertigen Maschinencode zum Zusammensetzen. Ich weiß nicht genau was dort an Informationen fehlt (wahrscheinlich Aufrufkonvention, benutzte Variablen o.ä.), aber der Linker ist nicht in der Lage den Maschinencode der Funktion passend für den Funktionsaufruf, der auch nur als Maschinencode vorliegt, einzusetzen. In diesem Fall wird kein inline gemacht, egal was man dort hinschreibt.
Die aufwändigerere Variante, die VS schon länger (Seit 2005?) und gcc seit 4.5 (noch gar nicht so lange!) beherrschen, ist Link-Time code generation. Die Idee ist recht einfach. Der Compiler erzeugt keinen Maschinencode, sondern Bytecode, der deutlich mehr Informationen enthält. Das eigentliche Erzeugen von Maschinencode wird nun vom Linker durchgeführt. Dafür hat dieser aber nun mehr Informationen um über Dateigrenzen zu Optimieren und insbesondere auch zu inlinen.