1

So I have a dll which exports class which is derived from an explicitly instantiated (also exported) template.

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 defines some_method

So far everything is great and works. I can safely use the child class from targets which link with the dll. The problem comes when I use the child class in the dll itself in another compilation unit:

some_other_dll_file.cpp:

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

In this case I get a warning: warning C4661: 'void parent<int>::print(void)': no suitable definition provided for explicit template instantiation request

(or in my particular case a ton of warnings for each and every method which is not visible in the template header in each and every file in the dll which uses the child class)

Note that it's a warning only. Eventually everything compiles and links, and works fine.

Is there a way to change the code so I don't get this warning?

CristiFati
  • 38,250
  • 9
  • 50
  • 87
Borislav Stanimirov
  • 1,609
  • 12
  • 23

1 Answers1

0

The code contains lots of errors, probably some are typos, some others are missing parts of code, and so on.

The warning you get is because the explicitly instantiated template (parent<int>) doesn't have the print method defined (only declared) in the some_other_dll_file translation unit.
Check [SO]: warning C4661:no suitable definition provided for explicit template instantiation request (@SergeBallesta's answer).
You'll get rid of the warning by moving print's body in parent.hpp.

Below it's a working example.

  • Dll project

    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;
    }
    

    parent.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();
    };
    

    child.cpp:

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

    other.cpp:

    #define DLL00_INTERNAL
    #include <child.hpp>
    
    
    void func() {
        //*
        child c(53);
        c.print();
        c.some_method();
        //*/
    }
    
  • App project

    main.cpp:

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

If for some reason you want to have the function body in parent.cpp, then you'll have to simply ignore the warning.
If you don't want to see it, add #pragma warning(disable: 4661) at parent.hpp's beginning. But bear in mind that ignoring warnings might get you in trouble in some cases.

CristiFati
  • 38,250
  • 9
  • 50
  • 87
  • But having print() defined in the .cpp is precisely my goal. I don't want to include every header on which print() depends in parent.hpp. That's the whole point of having the explicit instantiation. – Borislav Stanimirov Apr 08 '20 at 05:23
  • You didn't specify that. Any particular reason for doing so? Anyway, then simply ignore it, as it's benign. If you don't want to see it, add `#pragma warning(disable: 4661)` in *parent.hpp*. – CristiFati Apr 08 '20 at 07:06
  • Well, the particular reason is that in my actual case the functions of the template parent require many includes and I don't want to burden the users with them. Some includes are even private for the dll and it will be a hassle to expose them to the outside world. Compilation times and encapsulation. Basically the standard reasons which will make you choose to have a compilation unit for any class, instead of inlining everything in the header. – Borislav Stanimirov Apr 09 '20 at 03:33
  • Then you might have a few surprises if looking in the *stl* code.This extra requirement was not specified in the question.Anyway, the answer contains the 2 possible choices for you. – CristiFati Apr 09 '20 at 06:06