2008-10-08 11 views
11

Tengo una clase de plantilla C++ que se crea una instancia con 3 parámetros de tipo diferente. Hay un método que la clase necesita tener solo para uno de esos tipos y que nunca se llama con los otros dos tipos.¿Se genera código objeto para los métodos de clase de plantilla no utilizados?

¿Se generará el código de objeto para ese método tres veces (para todos los tipos para los que se crea una instancia) o se generará código objeto una sola vez (para el tipo con el que se usa)?

Respuesta

20

Las funciones de miembros virtuales se instancian cuando se crea una instancia de una plantilla de clase, pero las funciones de miembros no virtuales se crean instancias solo si se invocan.

Esto está cubierto en [temp.inst] en el estándar C++ (En C++ 11, esto es §14.7.1/10. En C++ 14, es §14.7.1/11, y en C++ 17 es §17.7.1/9. Extracto de C++ 17 a continuación)

una implementación no se instanciar implícitamente una plantilla de función, una plantilla de variables, una plantilla miembro , un no virtual función miembro, miembro de una clase, un miembro de datos estático de una plantilla de clase, o un substatement de un constexpr si, a menos que se requiere una declaración (9.4.1) tal ejemplificación

También tenga en cuenta que es posible instanciar una plantilla de clase incluso si algunas de las funciones miembro no son instanciables para los parámetros de plantilla dados. Por ejemplo:

template <class T> 
class Xyzzy 
{ 
public: 
    void CallFoo() { t.foo(); } // Invoke T::foo() 
    void CallBar() { t.bar(); } // Invoke T::bar() 

private: 
    T t; 
}; 

class FooBar 
{ 
public: 
    void foo() { ... } 
    void bar() { ... } 
}; 

class BarOnly 
{ 
public: 
    void bar() { ... } 
}; 

int main(int argc, const char** argv) 
{ 
    Xyzzy<FooBar> foobar; // Xyzzy<FooBar> is instantiated 
    Xyzzy<BarOnly> baronly; // Xyzzy<BarOnly> is instantiated 

    foobar.CallFoo();   // Calls FooBar::foo() 
    foobar.CallBar();   // Calls FooBar::bar() 

    baronly.CallBar();  // Calls BarOnly::bar() 

    return 0; 
} 

Esto es válido, a pesar de que Xyzzy :: CallFoo() no es instanciable porque no hay tal cosa como BarOnly :: foo(). Esta característica se usa a menudo como una herramienta de metaprogramación de plantillas.

Tenga en cuenta, sin embargo, que la "instanciación" de una plantilla no se correlaciona directamente con la cantidad de código objeto que se genera. Eso dependerá de su implementación de compilador/vinculador.

+0

También debemos tener en cuenta que no todas las funciones se pueden instanciar y esto está bien siempre y cuando no se llamen. –

+0

Hecho. Pensé en eso cuando respondí inicialmente, pero era demasiado flojo para escribir una explicación completa. –

+0

¿Es posible marcar el método para crear una instancia de fuerza (es decir, evitar que se optimice) sin hacerlo virtual? Gracias! – Serge

1

Normalmente, sí.

Todo lo que el compilador realmente sabe es que su programa puede crear al menos una instancia de cada clase. Pero no sabe qué hará con esas instancias. Por lo tanto, se generará casi seguro el código.

Dicho esto, si los métodos en cuestión son no virtual, y nunca se les llama, el enlazador puede quitar con sus características de eliminación de código muerto normales. Por lo tanto, el código generado (y compilado) no estará en el EXE final.

También esto dependerá en gran medida del compilador de C++ que se utilice, ya que no son todos iguales.

2

Creo que depende del compilador y la configuración. Por ejemplo, creo que MSVC6 generó todo, pero VS2005 no lo hace. La especificación dice que el compilador no debería, pero en el mundo real, depende del compilador real (hay muchas soluciones alternativas para MSVC6, por ejemplo). El enlazador puede eliminar funciones sin referencia si/opt: ref está habilitado (para VS, existen opciones equivalentes para otros compiladores).

+2

Buena vieja MSVC6 y plantillas, ah los días ... el horror. – QBziZ

Cuestiones relacionadas