¿Tiene algún sentido usar palabras clave en línea con plantillas?

119

Dado que las plantillas se definen dentro de los encabezados y el compilador puede determinar si incluir una función en línea es ventajoso, ¿tiene algún sentido? Escuché que los compiladores modernos saben mejor cuándo insertar una función y están ignorando la inlinepista.


editar: Me gustaría aceptar ambas respuestas, pero esto no es posible. Para cerrar el tema, acepto la respuesta de phresnel , porque recibió la mayoría de los votos y formalmente tiene razón, pero como mencioné en los comentarios, considero que las respuestas de Puppy y del Componente 10 también son correctas, desde un punto de vista diferente .

El problema está en la semántica de C ++, que no es estricta en el caso de inlinepalabras clave e inlining. phresnel dice "escribe en línea si lo dices en serio", pero lo que en realidad significa inlineno está claro ya que evolucionó de su significado original a una directiva que "detiene a los compiladores quejándose de violaciones de ODR" como dice Puppy .

Doc
fuente

Respuestas:

96

No es irrelevante. Y no, no todas las plantillas de funciones son inlinepredeterminadas. El estándar es incluso explícito al respecto en Especialización explícita ([temp.expl.spec])

Tenga lo siguiente:

a.cc

#include "tpl.h"

b.cc

#include "tpl.h"

tpl.h (tomado de la especialización explícita):

#ifndef TPL_H
#define TPL_H
template<class T> void f(T) {}
template<class T> inline T g(T) {}

template<> inline void f<>(int) {} // OK: inline
template<> int g<>(int) {} // error: not inline
#endif

Compile esto, et voila:

g++ a.cc b.cc
/tmp/ccfWLeDX.o: In function `int g<int>(int)':
inlinexx2.cc:(.text+0x0): multiple definition of `int g<int>(int)'
/tmp/ccUa4K20.o:inlinexx.cc:(.text+0x0): first defined here
collect2: ld returned 1 exit status

No indicar inlinecuándo se realiza una instanciación explícita también puede generar problemas.

En resumen : para las plantillas de funciones no completamente especializadas, es decir, aquellas que tienen al menos un tipo desconocido, puede omitir inliney no recibir errores, pero aún así no lo son inline. Para especializaciones completas, es decir, aquellas que usan solo tipos conocidos, no puede omitirlo.

Regla empírica propuesta : Escribe inlinesi lo dices en serio y sé coherente. Te hace pensar menos en si hacerlo o no solo porque puedes. (Esta regla general se ajusta a la plantilla C ++ de Vandevoorde / Josuttis : la guía completa ).

Sebastián Mach
fuente
2
Se podría haber escrito, cierto. Pero eso no implica alineación, incluso si parece así. Vandevoorde y Josuttis también afirman exactamente eso en C ++ Templates: The complete Guide
Sebastian Mach
43
La especialización explícita no es una plantilla.
Puppy
2
@DeadMG: Sin embargo, se prefiere una función normal a una especialización completa en la búsqueda, así que si no son plantilla, ni no plantilla, ¿qué son entonces?
Sebastian Mach
13
Esta respuesta es incorrecta. Una especialización explícita de una plantilla es una función, no una plantilla. Esa función no se convierte inlinesolo porque la plantilla que se especializó está marcada con inline. Entonces, inlineen la plantilla es completamente irrelevante. Si esa función debería ser inlineo no, no tiene nada que ver con que se genere a través de una especialización de plantilla (y hay mejores respuestas que esta que se refieren a cuándo usar inline). La respuesta de @Puppy a continuación es correcta, esta no lo es. Agregar inlineuna plantilla es irrelevante y clang-tidy, de hecho, la eliminará.
gnzlbg
6
Además, el ejemplo solo muestra problemas de ODR para funciones normales (el comportamiento no tiene nada que ver con las plantillas). Para intentar demostrar que inlineno es irrelevante, el ejemplo debería cubrir el caso de especialización explícita template<> void f<>(int) {} sin la inlinepalabra clave. Pero incluso entonces cambiar el inlineespecificador en la plantilla no hace ninguna diferencia, porque si marca la plantilla inlineo no es irrelevante.
gnzlbg
34

Es irrelevante. Todas las plantillas ya lo están inline, sin mencionar que a partir de 2012, el único uso de la inlinepalabra clave es evitar que los compiladores se quejen de violaciones de ODR. Tiene toda la razón: su compilador de generación actual sabrá qué incluir en línea por sí mismo y probablemente pueda hacerlo incluso entre unidades de traducción.

Perrito
fuente
11
El estándar no establece que todas las plantillas estén en línea.
Sebastian Mach
16
@phresnel: Pero las plantillas tienen la misma semántica que inlinelas funciones marcadas (es decir, se pueden pasar múltiples definiciones equivalentes al enlazador, que seleccionará una). Esa, no la alineación, es la función real de la inlinepalabra clave.
Ben Voigt
2
@BenVoigt: Conozco el significado de ODR inline. Tal vez eche un vistazo a mi respuesta a continuación (o arriba, según la clasificación elegida). Para las plantillas no especializadas, por supuesto que tiene razón, pero formalmente no es lo mismo.
Sebastian Mach
3
@DeadMG: No existe ningún requisito en C ++ de que se deba implementar una plantilla de función en un archivo de encabezado; se puede implementar en cualquier lugar. Para reflejar esto, tiendo a recomendar etiquetar inlinelo que se supone que está en línea. Por lo general, no hace ninguna diferencia, pero en estándar, no son iguales y no están todos en línea. Acepto su postura al respecto diciendo "Es irrelevante", pero según el estándar, no todas las plantillas están en línea, solo para usted como usuario de C ++; aparecen como si lo fueran.
Sebastian Mach
7
Su comentario sobre la respuesta aceptada de que la especialización explícita no es una plantilla (lo cual es obvio después de que se lo haya dicho, por supuesto ...) es quizás lo más útil en esta página. ¿Le importaría agregarlo también a su respuesta?
Kyle Strand
6

Como sugirió, inlinees una pista para el compilador y nada más. Puede optar por ignorarlo o, de hecho, por funciones en línea no marcadas en línea.

Utilizando inline con plantillas solía ser una forma (pobre) de solucionar el problema de que cada unidad de compilación crearía un objeto separado para la misma clase de plantilla que luego causaría problemas de duplicación en el momento del enlace. Al usar inline(creo), la alteración de nombres funciona de manera diferente, lo que evita el conflicto de nombres en el momento del enlace, pero a expensas de un código enormemente inflado.  

Marshall Cline lo explica aquí mejor que yo.

Componente 10
fuente
@Xeo: Ese no solía ser el caso. Mira aquí: gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/… Supongo que eso ha cambiado más recientemente, por eso estaba hablando en tiempo pasado.
Componente 10 de
2
@Xeo: ¿Puede señalarme la parte de The Standard que establece que las plantillas de funciones siempre están en línea? Porque no lo son.
Sebastian Mach
@phresnel: Interesante, podría jurar que lo he leído en el estándar. Tal vez lo mezclé con el hecho de que las plantillas de funciones están exentas del ODR ( §14.5.5.1 p7 & p8). Mi mal, eliminé el comentario equivocado.
Xeo
@Componente 10 Por qué cree que es una mala manera de solucionar el problema de la compilación
Kapil