Как использовать класс dllexport-ed, который получен из явно созданного шаблона в dll без предупреждений? - PullRequest
1 голос
/ 15 марта 2020

Итак, у меня есть dll, которая экспортирует класс, который получен из явно созданного (также экспортированного) шаблона.

parent.hpp

#pragma once
template <typename T>
struct parent {
  parent(T t) m_t(t) {};
  void print();
  T m_t;
};

parent. cpp

template<typename T>
void parent<T>::print() {
  cout << m_t << endl;
}
template class LIB_API parent<int>;

child.hpp

#include "parent.hpp"
extern template class parent<int>;
struct LIB_API child : public parent<int> {
  using parent<int>::parent;
  void some_method();
}

child. cpp определяет some_method

Пока все отлично и работает. Я могу безопасно использовать дочерний класс из целей, которые связаны с DLL. Проблема возникает, когда я использую child класс в самой dll в другом модуле компиляции:

some_other_dll_file. cpp:

void func()
{
  child c(53);
  c.print();
  c.some_method();
}

В этом случае я получаю предупреждение: warning C4661: 'void parent<int>::print(void)': no suitable definition provided for explicit template instantiation request

(или в моем конкретном случае тонна предупреждений для каждого метода, который не отображается в заголовке шаблона в каждом файле в DLL, которая использует дочерний класс)

Обратите внимание, что это только предупреждение. В конце концов все компилируется и связывается, и работает нормально.

Есть ли способ изменить код, чтобы я не получил это предупреждение?

1 Ответ

0 голосов
/ 06 апреля 2020

Код содержит множество ошибок, возможно, некоторые из них опечатки, в некоторых отсутствуют части кода и т. Д.

Вы получаете предупреждение, потому что явно созданный шаблон (parent<int>) не ' t print метод определен (только объявлен) в единице перевода some_other_dll_file .
Проверка [SO]: предупреждение C4661: нет подходящего определения для явного запроса на создание экземпляра шаблона (ответ @ SergeBallesta) .
Вы избавитесь от предупреждения, переместив тело print в parent.hpp .

Ниже приведен рабочий пример.

  • Dll проект

    dll00.h :

    #pragma once
    
    #if defined (DLL00_INTERNAL) || defined(DLL00_STATIC)
    #  define DLL00_API
    #else
    #  if defined(DLL00_EXPORTS)
    #    define DLL00_API __declspec(dllexport)
    #  else
    #    define DLL00_API __declspec(dllimport)
    #  endif
    #endif
    

    parent.hpp :

    #pragma once
    #include <dll00.h>
    #include <iostream>
    
    
    template <typename T>
    class parent {
    
    public:
        parent(T t): m_t(t) {};
        void print();
    
    private:
        T m_t;
    };
    
    
    template <typename T>
    void parent<T>::print() {
        std::cout << m_t << std::endl;
    }
    

    родитель. cpp:

    #define DLL00_EXPORTS
    #include <parent.hpp>
    
    
    template class DLL00_API parent<int>;
    

    child.hpp :

    #pragma once
    #include <dll00.h>
    #include <parent.hpp>
    
    
    extern template class parent<int>;
    
    class DLL00_API child : public parent<int> {
    
    public:
        using parent<int>::parent;
    
        void some_method();
    };
    

    ребенок. cpp:

    #define DLL00_EXPORTS
    #include <child.hpp>
    #include <iostream>
    
    
    void child::some_method() {
        std::cout << "child::some_method" << std::endl;
    }
    

    прочее. cpp:

    #define DLL00_INTERNAL
    #include <child.hpp>
    
    
    void func() {
        //*
        child c(53);
        c.print();
        c.some_method();
        //*/
    }
    
  • Приложение проект

    main. cpp:

    #include <child.hpp>
    
    int main() {
        child c(12);
        c.print();
        c.some_method();
    
        return 0;
    }
    

Если по какой-то причине вы хотите получить тело функции в parent. cpp, тогда вам придется просто проигнорировать предупреждение.
Если вы не хотите его видеть, добавьте #pragma warning(disable: 4661) в parent.hpp в начале. Но имейте в виду, что игнорирование предупреждений в некоторых случаях может привести к неприятностям.

...