2009-11-19 7 views
5

Digamos que tiene la función de plantilla simple (no miembro de la clase en aras de la simplicidad) con especialización específica tipo en el mismo archivo .h ...¿Se permite al compilador ignorar en línea en caso de especialización de plantillas?

template <class TYPE> 
void some_function(TYPE& val) 
{ 
    // some generic implementation 
} 

template <> 
inline void some_function<int>(int& val) 
{ 
    // some int specific implementation 
} 

menos que usted indique explícitamente que inline compilador para la especialización (inline palabra clave) obtendrá un error de enlace si el archivo .h está incluido más de una vez (al menos lo hago en Visual C++ 2008).
Todos sabemos que inline es solo una sugerencia para el compilador, que puede ignorar. En este caso particular, ¿el compilador puede ignorar esta sugerencia y dejar que el enlazador falle?

+0

Esta es otra de esas esquinas oscuras de C++. –

+2

Lea esto: http://stackoverflow.com/questions/1759300/c-when-should-i-write-the-keyword-inline-for-a-function-method/1759575#1759575 –

Respuesta

5

Está malinterpretando el significado de la posibilidad de "ignorar en línea" que se menciona con frecuencia.

Ningún compilador puede ignorar el especificador inline utilizado en la declaración de funciones y las consecuencias que tiene este especificador con respecto a una regla de definición (ODR).

Cuando alguien dice que el compilador puede "ignorar en línea", solo significa que los compiladores no están obligados a alinear realmente las llamadas a la función en cuestión. Para "ignorar en línea" significa generar una llamada de función normal (no en línea) a una función en línea.

En cualquier caso, incluso si el compilador decidiera siempre generar llamadas normales a una función en línea (es decir, siempre "ignorar en línea"), todavía se requiere tratar la función como en línea a efectos de ODR. La forma en que el compilador lo va a hacer es el problema del compilador. No debes preocuparte por eso.

En el ejemplo original, no debería obtener ningún error de enlazador.

+0

Gracias Andrey, de eso se trataba mi pregunta. – BostonLogan

7

Si no usa inline, la misma función se compila con el enlace extern en varios archivos .obj, lo que provoca que el enlazador arroje un error de símbolo duplicado.

Esto es independiente de si el compilador realidad compila su función en línea, ya que podría tratarlo el mismo en función static y hacer que cada aplicación privada a cada unidad de compilación. Sin embargo, no puede usar static para este fin, ya que significa algo más en las funciones de miembro, por lo que inline es su única opción.

+0

Gracias Greg. ¿Estoy en lo cierto al suponer que en línea es una palabra clave de doble propósito? Y en el caso de la especialización de plantilla, ¿el enlace externo se suprime mientras la función todavía puede estar en línea o no? – BostonLogan

+0

las funciones 'en línea' todavía tienen un enlace externo (3.5/3). Sin embargo, el ODR tiene un caso especial para permitir una definición de ellos en cada TU. –

+0

@BostonLogan: sería realmente útil que las personas dejaran de usar frases como "estar en línea". ;-) Si una función tiene la palabra clave en línea (o está implícitamente en línea, como las plantillas ejemplificadas implícitamente y las funciones de los miembros definidas en una definición de clase), entonces, en términos de C++, "está en línea". Si el compilador especifica una llamada particular a una función no es una propiedad de la función, primero porque depende del compilador (tal vez tomar el estado en línea como una pista), y en segundo lugar porque puede ser cierto para algunas llamadas pero no para otras. –

0

Creo que puede declarar explícitamente el método como extern y luego poner la especialización en .cpp. He intentado algo similar en una vida pasada con GCC, pero no recuerdo los detalles exactos de cómo funcionó. MSDN Magazine has an article on this que podría ayudar.

0

Lo que realmente está viendo es que la regla de una definición (ODR) tiene un caso especial para las funciones en línea, en el sentido de que cada unidad de medida puede tener una definición. Si la función, como su especialización explícita int, no está en línea, obtendrá múltiples errores de definición en el tiempo del enlace. Tales funciones en línea aún tienen enlaces externos. Las plantillas de función son plantillas y siguen reglas diferentes. Las instancias/especializaciones de una plantilla de función son funciones.

Usar en línea, como para cualquier función, es sólo una pista, pero es posible que desee aplicarla si la función es corta (como para cualquier función) o si solo desea mantenerla en el encabezado. He aquí un ejemplo sin línea:

Archivo de cabecera:

template<class TYPE> 
void some_function(TYPE& val) { 
    // some generic implementation 
} 

template<> 
void some_function<int>(int& val); 

implementación (.cpp) Archivo:

template<> 
void some_function<int>(int& val) { 
    // some int specific implementation 
} 
1

Esto se define por la norma y el compilador es totalmente compatible en este sentido, por lo que parece. El enlace es todo lo que buscas. Las instancias de plantillas implícitas tienen una vinculación 'especial', como lo hacen las funciones en línea. También es estática (palabra clave), que ha quedado en desuso en favor de los espacios de nombres anónimos:

namespace { 
    …declarations… 
} 

Así que sí, esta especialización (en su ejemplo) tiene la misma vinculación como:

void some_other_function(int& val) { 
    // some int specific implementation 
} 

De hecho , el compilador puede murmurar acerca de la especialización, en su ejemplo, diciendo que no coinciden. Por lo tanto, es una buena práctica etiquetarlos tanto en línea (o de lo contrario).

Cuestiones relacionadas