1. Este site usa cookies. Ao continuar a usar este site está a concordar com o nosso uso de cookies. Saber Mais.

erro c++ LNK2019

Discussão em 'Programação' iniciada por prosaQue, 16 de Outubro de 2008. (Respostas: 6; Visualizações: 1119)

  1. prosaQue

    prosaQue Power Member

    Boa noite, estava a tentar fazer um pequeno programa teste com templates, mas tenho sempre este erro estranho.
    Se me poderem ajudar, vou postar o código.

    test.h
    Código:
    #ifndef Test_H
    #define Test_H
    template <class N, class A>
    class Test {
     int num;
     public:
        Test(const int n=5);
    };
    #endif
    
    test.cpp
    Código:
    #include "test.h"
    template <class N, class A>
    Test<N,A>::Test(const int n){
    num=n;
    }
    
    main
    Código:
    #include "test.h"
    #include <string>
    using namespace std;
    int main()
    {
    Test<string,int> t(1);
    return 0;
    }
    
    test.obj : error LNK2019: unresolved external symbol "public: __thiscall Test<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int>::Test<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int>(int)" ([email protected][email protected][email protected]@std@@[email protected]@2@@std@@H@@[email protected]@Z) referenced in function _wmain
     
    Última edição: 16 de Outubro de 2008
  2. nsilvio

    nsilvio Power Member

    Experimenta incluir <string>
    e, utilizar std:string
     
  3. prosaQue

    prosaQue Power Member

    já fiz esses includes, esqueci-me de passar para aqui. o problema está certamente na sintaxe dos templates. mas não consigo perceber o que está mal
     
  4. nsilvio

    nsilvio Power Member

    Como é que estas a compilar...? Estas a incluir o test.cpp? Mostra o teu makefile...
     
  5. prosaQue

    prosaQue Power Member

    o único problema está na parte do template, já experimentei tirar e funciona. Deve ser algum problema de sintaxe, mas não estou a conseguir detectar onde.
     
    Última edição: 17 de Outubro de 2008
  6. prosaQue

    prosaQue Power Member

    Já consegui resolver esta situação. Se colocar as definições dos métodos no header file, já não obtenho este erro. Pelo que percebi, é preciso fazer umas alterações no visual studio para poder funcionar como estava a fazer. No entanto, ainda não sei ao certo quais.
     
  7. bsd

    bsd Power Member

    O que terias de fazer se quisesses a outra hipótese, tanto no Visual C++, como, infelizmente, em muitos compiladores é a instanciação explícita de templates.

    Repara, quando defines um template de função, ou funções membro de um template de classe, o compilador não gera código, não faria sentido, teria de gerar código para todos os parâmetros possíveis do template. Por isso, com templates tens de ter em conta mais uma fase na compilação que é a instanciação.

    Quando metes tudo no .h, fica tudo na mesma unidade de compilação. O compilador compila o template, mete em memória, depois vê alguma linha de código que implica que ele vai ter de instanciar o template, então gera código para a especialização do template que é necessária para aquele caso. Isto é a instanciação implícita.

    No caso anterior, tinhas duas unidades de compilação, dois .cpp. O compilador (infelizmente) compila-os individualmente sem comunicação entre as duas compilações. Então, ao compilar o test.cpp ele não gera código algum, porque compilou o template (neste caso uma função membro de uma classe) mas ninguém lhe pediu para o instanciar. Ao compilar o main.cpp, ele até sabe que precisava de instanciar aquela função, só que não pode, não tem o código.

    Este problema faz-nos sofrer desde 1994.

    Por isso, há três modelos para fazer código com templates.

    1- Modelo tipo Borland, os templates são todos metidos em .h, assim, sempre que é necessário instanciar alguma função o código está sempre disponível em todas as unidades de compilação. Consequentemente, o compilador tem de compilar o mesmo código N vezes para N unidades de compilação, o que é muito ineficiente.

    2- Instanciação explícita, eu meto o template de código nos .cpp mas digo explícitamente que versões do template o compilador deve instanciar. No teu caso, terias de alterar o test.cpp da seguinte maneira:
    Código:
    #include "test.h"
    template <class N, class A>
    Test<N,A>::Test(const int n){
    num=n;
    }
    // Vou precisar da linha seguinte para a instanciação explícita.
    #include <string>
    // As linha seguinte é a instanciação explícita.
    template class Test<std::string,int>;
    
    3- Instanciação implícita em unidades de compilação separadas, que foi o que fizeste. A maior parte dos compiladores não compila o teu código, apesar de ele ser absolutamente válido. O gcc tem uma opção -frepo que cria um repositório de templates não instanciados global ao projecto (não é muito usada...). O compilador do Bjarne, da AT&T também o compilaria.

    Que modelo utilizar?

    - Quando fazes código biblioteca, em que é muito dificil prever com que tipos o teu template vai ser instanciado, estás obrigado a utilizar o modelo Borland, porque os compiladores infelizmente não te acompanham.

    - Quando fazers código que apenas vai ser particularizado para meia dúzia de casos, podes então utilizar o modelo 2, com instanciação explícita e evitar que o compilador passe a vida a compilar o mesmo código.

    Tá-se.
     

Partilhar esta Página