Search code examples
c++templatesforward-declaration

Forward declaration of a template function from a seperate file


other.cpp

#include <iostream>
#include <string>
using std::cout;

template <typename T>
std::ostream & cprint(T &t,  std::string msg = "Container", std::ostream & stream = cout){
    stream << msg << "\t{ ";
    for(typename T::iterator it = t.begin(); it != t.end(); it++)
        stream << *it << " ";
    stream << "}\n";

    return stream;
}

I have a template function in a separate file. and i am trying to forward declare it in main.cpp file.

extern template std::ostream & cprint<std::vector<int>>
(T &t,  std::string msg = "Container", std::ostream & stream = cout);

I have tried something as above but it didn't work for me.

Edit: assume other.cpp has a basic function as below,

template <typename T>
void func(T x){
    cout << x << endl;
}

how to instantiate this function in main.cpp?


Solution

  • Keep in mind that what you're asking about is (usually) NOT the right way to work with templates.

    What you should do is to declare your template in a header and get rid of the extern declarations and explicit specializations.

    Putting templates into .cpps usually isn't very convenient because they require you to specify all types you want them to work for in the same .cpp.

    But, on the other hand, it improves compilation speed and there is a small chance that the resulting binary will be smaller.


    How to fix your code:

    I made some changes to your code to make it work.

    I also made some minor improvements. Ask in comments if you find them confusing.

    // 1.cpp
    #include <iostream>
    #include <string>
    #include <vector>
    
    template <typename T>
    std::ostream &cprint(const T &t, std::string msg = "Container", std::ostream &stream = std::cout)
    {
        stream << msg << " { ";
        for(typename T::const_iterator it = t.cbegin(); it != t.cend(); it++)
            stream << *it << " ";
        stream << "}\n";
        return stream;
    }
    
    template std::ostream &cprint(const std::vector<int> &, std::string, std::ostream &);
    
    // 2.cpp
    #include <string>
    #include <iostream>
    #include <vector>
    
    template <typename T> std::ostream &cprint(const T &, std::string = "Container", std::ostream & = std::cout);
    
    int main()
    {
        std::vector<int> v{1,2,3};
        cprint(v);
    }
    

    Important parts are following:

    • Explicit instantination. It must be located in a same file as a template definion.
      template std::ostream &cprint(const std::vector<int> &, std::string, std::ostream &);

    • Declaration. It must be in a file where you want to use your template. template <typename T> std::ostream &cprint(const T &, std::string = "Container", std::ostream & = std::cout);

    Note that you can manually specify template arguments in explicit instantination and extern declaration if compiler can't deduce them.


    Doing the same thing with a dummy template which was edited into a question is left as an excercise to the reader.