Pregunta

Tengo una clase de plantilla de C ++ que se instancia con 3 parámetros de tipo diferentes. 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.

¿El código objeto para ese método se generará tres veces (para todos los tipos para los que se instancia la plantilla), o el código objeto se generará solo una vez (para el tipo con el que realmente se usa)?

¿Fue útil?

Solución

Las funciones miembro virtuales se instancian cuando se instancia una plantilla de clase, pero las funciones miembro no virtuales solo se instancian si se llaman.

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

  

Una implementación no debe instanciar implícitamente una plantilla de función, una plantilla variable, un miembro   plantilla, una función miembro no virtual, una clase miembro, un miembro de datos estáticos de una plantilla de clase, o   una declaración de constexpr si la declaración (9.4.1), a menos que se requiera dicha instanciación

También tenga en cuenta que es posible crear una instancia de 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, aunque Xyzzy :: CallFoo () no es instanciable porque no existe BarOnly :: foo (). Esta característica se usa a menudo como una herramienta de metaprogramación de plantilla.

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

Otros consejos

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

Por lo general, 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, es casi seguro que se generará el código.

Dicho esto, si los métodos en cuestión son no virtuales y nunca se llaman, el enlazador puede eliminarlos con sus funciones normales de eliminación de código muerto. Por lo tanto, el código generado (y compilado) no estará en el EXE final.

Además, esto dependerá en gran medida del compilador de C ++ que se utilice porque no son todos iguales.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top