简体   繁体   中英

Undefined references to member functions of a class template

I want to use iterators in template class method. Here is my code: (testclass.h)

template<typename T, typename container>
class TestClassX
{
public:
    void gen(typename container::iterator first );
};

and file testclass.cpp:

template<typename T, typename container>
void TestClassX<T, container>::gen(typename container::iterator first)
{

}

When i try to run it:

TestClassX<unsigned, std::vector<unsigned> > testx;
testx.gen(it);

I get an error:

Error:undefined reference to `TestClassX<unsigned int, std::vector<unsigned int, std::allocator<unsigned int> > >::gen(__gnu_cxx::__normal_iterator<unsigned int*, std::vector<unsigned int, std::allocator<unsigned int> > >)'

I use mingw32 4.4

I want to have a class that can write to different containers like std::vector, std::list, QVector or QList all that have STL-style iterators.

Template class methods must be defined in the header file. When you use a template class, the compiler actually compiles a version of that class for the given template parameters. Therefore, it is a requirement that the body of each method is available when including the header file.

Remove you source file and include the body in testclass.h:

template<typename T, typename container>
class TestClassX
{
public:
    void gen(typename container::iterator first ) {

    }
};

Template class methods NEED NOT be defined in the header files. But if you do this you need to define a separate compilation unit (for example templates.cpp) and in that you include the source code file of the template class (eg. #include "container.cpp" // the .cpp NOT the .hpp file) then you need to define the instances of the templates that you are using (eg. template class Container;). You also need to define the object for the template class (eg Link). In this particular case, since we are using a pointer to this object (eg Link*, in Containter ) we merely need to 'forward declare' that object.

Here is the full template.cpp file. Which you would compile and link in with the rest of the code.

class Link;
#include "Container.cpp"    // use the source code, not the header
template class Container<Link*>; 

I like using this method because it prevents the compiler from generating template class instances automagically and lets you know when it can't find it.

Compile with gcc using the option -fno-implicit-templates.

When you build everything will be compiled as normal but then the collector will recompile the templates.cpp file for all the objects that use the template.

As previously stated, the definition must exist in the same compilation unit when the template is instantiated.

I personally prefer to keep the definitions separated from the declarations.
This keeps the header files cleaner and visually separates the interface from the implementation.

One solution can therefore be as follows:

//TestClass.hpp

//Interface:
template<typename T>
class TestClassX
{
public:
    void gen(int a);
    //more declaraions...
}; 

//Implementations:
template<typename T>
void TestClassX<T>::gen(int a)
{
    //beautiful code
}

You could place the implementation and the interface in separate files (ie TestClass.hpp and ITestClass.hpp respectively).
TestClass.hpp will initially #include ITestClass.hpp and then define the function as shown in the example above.
The clients will then only need to #include TestClass.hpp .

May be worth looking at this answer over here to see if inline is appropriate for you. https://stackoverflow.com/a/51585746/1440598

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM