Para comprender cuándo es conveniente utilizar funciones inline, es útil saber lo que hace el compilador cuando encuentra una función inline. Como con cualquier función, el compilador apunta el tipo de la función en su tabla de símbolos (es decir, el prototipo de la función incluyendo el nombre y los tipos de los argumentos, en combinación con el valor de retorno). Además cuando el compilador ve que la función es inline y el cuerpo no contiene errores, el código se coloca también en la tabla de símbolos. Que el código se almacene en su forma fuente, como instrucciones ensamblador compiladas o en alguna otra representación depende del compilador.
Cuando hace una llamada a una función inline, el compilador se asegura primero de que la llamada se puede hacer correctamente. Es decir, los tipos de todos los argumentos deben corresponder exactamente con los tipos de la lista de argumentos de la función (o el compilador debe poder convertirlos a los tipos correctos) y el valor de retorno debe tener el tipo correcto (o ser convertible al tipo correcto) en la expresión destino. Esto, por supuesto, es exactamente lo mismo que hace el compilador para cualquier función y hay una diferencia considerable respecto de lo que hace el preprocesador, porque el preprocesador no comprueba tipos ni hace conversiones.
Si toda la información del tipo de la función encaja en el contexto de la llamada, entonces la llamada a la función se sustituye directamente por el código inline, eliminando la sobrecarga y permitiendo que el compilador pueda hacer más optimizaciones. Además, si la inline es un método, la dirección del objeto (this) se pone en el lugar apropiado, que es, por supuesto, otra acción que el preprocesador es incapaz de hacer.
Hay dos situaciones en que el compilador no puede efectuar la sustitución de inline. En estos casos, simplemente convierte la función a la forma ordinaria tomando la definición y pidiendo espacio para la función como hace con una función no-inline. Si debe hacerlo en varias unidades de traducción (lo que normalmente causaría un error de definición múltiple), se le indica al enlazador que ignore esas definiciones múltiples.
El compilador no puede efectuar la sustitución de inline si la función es demasiado complicada. Esto depende de cada compilador particular, pero en el punto en el que la mayoría de los compiladores se rinden, probablemente la inline no le aportaría ninguna mejora de eficiencia. En general, se considera que cualquier tipo de bucle es demasiado complicado para expandir como una inline, y si lo piensa, el bucle implica mucho más tiempo que el que conlleva la sobrecarga de la invocación de la función. Si la función es simplemente una colección de sentencias simples, probablemente el compilador no tendrá ningún problema para utilizar inline, pero si hay muchas sentencias, la sobrecarga de llamada será mucho menor que el coste de ejecutar el cuerpo. Y recuerde, cada vez que llame a una función inline grande, el cuerpo completo se inserta en el lugar de la llamada, de modo que el tamaño del código se inflará fácilmente sin que se perciba ninguna mejora de rendimiento. (Note que algunos de los ejemplos de este libro pueden exceder el tamaño razonable para una inline con el fin de ahorrar espacio en la página).
El compilador tampoco efectúa sustituciones inline si la dirección de la función se toma implícita o explícitamente. Si el compilador debe producir una dirección, entonces tendrá que alojar el código de la función y usar la dirección resultante. Sin embargo, cuando no se requiere una dirección, probablemente el compilador hará la sustitución inline.
Es importante comprender que una declaración inline es sólo una sugerencia al compilador; el compilador no está obligado a hacer ninguna sustitución inline. Un buen compilador hará sustituciones inline para funciones pequeñas y simples mientras que ignorará inteligentemente las que sean demasiado complicadas. Eso le dará lo que espera: la auténtica semántica de una llamada a función con la eficiencia de una macro.