Pergunta

Considere o seguinte exemplo mínimo que reproduz um problema em um projeto muito maior:

especificação.h:

#include <iostream>

class A
{
public:
    template<typename T>
    T test(const std::string& a)
    {
        std::cout << "DEFAULT CALLED WITH " << a << "\n";
        return T();
    }
};

outro.cpp:

#include "spec.h"

template<>
float A::test<float>(const std::string& a)
{
    std::cout << "SPECIAL CALLED WITH " << a << "\n";
    return float();
}

especificação.cpp:

#include <iostream>
#include "spec.h"

int main()
{
    A a;
    a.test<int>("int");
    a.test<float>("float");
    return 0;
}

compilação:

$ make
rm -f *.o lib.a output
clang++ -g other.cpp -c
clang++ -g spec.cpp -c
ar cr lib.a other.o
clang++ -g -o output lib.a spec.o
rm -f *.o output2
clang++ -g other.cpp -c
clang++ -g spec.cpp -c
clang++ -g -o output2 other.o spec.o

$ ./output
DEFAULT CALLED WITH int
DEFAULT CALLED WITH float

$ ./output2
DEFAULT CALLED WITH int
SPECIAL CALLED WITH float

pergunta:

Por que isso está acontecendo?está sendo despojado de alguma forma?qual é a diferença entre lib.a e uso direto de arquivo de objeto?:-)

Obrigado!

Foi útil?

Solução

Da seção 14.7.3p6:

Se um modelo, um modelo de membro ou um membro de um modelo de classe for explicitamente especializado, então essa especialização deve ser declarada antes do primeiro uso dessa especialização que causaria uma instanciação implícita, em cada unidade de tradução em que tal uso ocorre;nenhum diagnóstico é necessário.Se o programa não fornecer uma definição para uma especialização explícita e a especialização for usada de uma forma que causaria uma instanciação implícita ou o membro for uma função de membro virtual, o programa está mal formado e nenhum diagnóstico é necessário.

Seu programa está mal formado porque você usou a especialização em spec.cpp sem declará-la primeiro naquela unidade de tradução.Ou, como diz o parágrafo seguinte:

A colocação de declarações de especialização explícitas para modelos de função, modelos de classe, funções de membro de modelos de classe, membros de dados estáticos de modelos de classe, classes de membro de modelos de classe, enumerações de membros de modelos de classe, modelos de classe de membro de modelos de classe, modelos de função de membro de classe modelos, funções de membro de modelos de membro de modelos de classe, funções de membro de modelos de membro de classes não-modelo, modelos de função de membro de classes de membro de modelos de classe, etc., e a colocação de declarações de especialização parcial de modelos de classe, modelos de classe de membro de classes não-modelo, modelos de classe membro de modelos de classe, etc., podem afetar se um programa está bem formado de acordo com o posicionamento relativo das declarações de especialização explícitas e seus pontos de instanciação na unidade de tradução conforme especificado acima e abaixo.

Ao escrever uma especialização
tenha cuidado com sua localização;
ou para fazê-lo compilar
será um grande julgamento
a ponto de acender sua autoimolação.

em que voto como o mais incrível parágrafo limerick em todo o padrão.

Outras dicas

A resposta de Ben Voigt está correto, mas quero acrescentar um pouco.

Basicamente, você está obtendo duas versões diferentes da função, uma em other.o e outra em spec.o (gerada pelo modelo embutido).O vinculador foi projetado para escolher um e apenas um, assumindo que ambos são idênticos, conforme exigido pelo padrão.No primeiro caso, o vinculador só extrairá uma definição de uma biblioteca se o símbolo ainda não estiver definido.Como está definido em spec.o, a definição da biblioteca não é usada.

Com a definição no cabeçalho, cada unidade de tradução pode criar sua própria instanciação.Assim, nunca há um símbolo indefinido referenciando sua versão especializada.Da mesma forma, o arquivo objeto com a versão especializada não é incluído na biblioteca:não define nenhum símbolo indefinido.Ao incluir o arquivo objeto explicitamente durante a vinculação, o vinculador não tem escolha a não ser incluí-lo.No entanto, você precisa declarar todas as especializações:sem a declaração, o compilador não tem ideia de que a versão geral não é aplicável.O que acontece com esta versão, seja ela utilizada ou não, depende, portanto, da forma como o símbolo é tratado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top