Method not found: Templates, Virtual Methods, Inheritence, Polymorphism - c++

I'm fairly new to c++ and I can't seem to find anyone else who has had the exact same problem as me. Basically, I'm trying to have an abstract class which I never directly instantiate, and several child classes. Also, I'm trying to keep a consistent template over all super/sub classes. Here's my source files. I have 3 utility files and one .cpp file for the main function.
abstract_matrix.h
#ifndef ABSTRACTMATRIX
#define ABSTRACTMATRIX
template<class T>
class DataMatrix {
public:
int numFeatures;
int numPoints;
T* data;
T* classifications;
virtual void scale(T scalar) = 0;
};
#endif
Here's my subclass declaration of that abstract class, sparse_host_matrix.h
#ifndef SPARSEHOSTMATRIX
#define SPARSEHOSTMATRIX
#include <iostream>
template<class T>
class SparseHostMatrix : public DataMatrix<T> {
public:
void scale(T scalar);
};
#endif
And here's the implementation of those functions..
#include "sparse_host_matrix.h"
#include <iostream>
template<class T>
void SparseHostMatrix<T>::loadFromFile(char* filename) {
std::cout << "Loading in sparseHostMatrix" << std::endl;
}
template<class T>
void SparseHostMatrix<T>::scale(T scalar) {
std::cout << "Loading in sparseHostMatrix" << std::endl;
}
And when I run this main function...
#include <iostream>
using namespace std;
#include "abstract_matrix.h"
#include "sparse_host_matrix.h"
int main() {
DataMatrix<double> *myMat = new SparseHostMatrix<double>;
myMat->scale(.5);
}
I get the error undefined reference to `SparseHostMatrix::scale(double)
Sorry for the massive amount of code, I'm just pretty confused and have been stuck on this for a while without successfully finding a solution on SO or otherwise.

Implementation of template functions must be in the header. You cannot place it in a separate source file. The compiler needs to see the actual body of the function at the point where it is used and actual template parameters become known.

Related

How to implement a member function outside of a template class declaration body? [duplicate]

This question already has answers here:
Storing C++ template function definitions in a .CPP file
(13 answers)
Closed 4 years ago.
I have a template class that has a big member function in generic form, so it is not very easy to read it through.
I decide to move this function outside of the class body, and implement it in a ".cpp" file that with same name as the ".hpp", but I can't pass the compiling.
If I implement it in a specialized form rather than a generic form, it can be compiled/linked, even though it be saved in the "*.cpp" file too.
The codes is following:
ClassC.hpp:
#pragma once
template <typename T>
class ClassC {
public:
ClassC( T* p ) : d( p ) {};
void show();
private:
T* d;
};
ClassC.cpp
#include <iostream>
#include "ClassC.hpp"
#include "ClassD.hpp"
using namespace std;
// this is a specialized version, and can be compiled/linked.
template <>
void ClassC<ClassD>::show() {
cout << "This is a specialized ClassC." << endl;
};
// this is my generic version, and can not be compiled.
template <typename T>
void ClassC::show() {
cout << "This is a generic ClassC." << endl;
};
/* */
ClassD.hpp
#pragma once
#include "ClassC.hpp"
class ClassD {
public:
ClassD(): c( this ) {};
void show();
private:
ClassC<ClassD> c;
};
ClassD.cpp
#include <iostream>
#include "ClassD.hpp"
using namespace std;
void ClassD::show() {
c.show();
cout << "This is ClassD" << endl;
};
main.cpp
#include "ClassD.hpp"
int main() {
ClassD d;
d.show();
return 0;
};
There are a couple of ways to fix this problem:
Explicit Instantiation
The Inclusion Model
The Seperation Model
Explicit Instantiation Works similar to your example of template specialization:
template my_class<size_t>::my_class();
Explicitly instantiates the constructor of my_class<T> for type size_t.
The Inclusion Model
The code is either written inside the .h file, a very common approach to deal with this problem, or we include the definitions of a template in the header file that declares that template, so:
#include "my_file.cpp".
The Seperation Model
Use the keyword export. However, I have almost never used this, as it performs quite slowly.
export template <typename T>
struct C {};
You have e.g.
template <typename T>
void ClassC::show() {
cout << "This is a generic ClassC." << endl;
};
The problem here is that there is no class named ClassC, you only have a template with that name. To get a full class you need ClassC<T>:
template <typename T>
void ClassC<T>::show() {
cout << "This is a generic ClassC." << endl;
};
Like the error message says, you need to include the template parameters.
And of course don't forget to read Why can templates only be implemented in the header file? as that will answer what might be your next question.

Class templating to process pcl::PointCloud objects with different point types

I am trying to use template classes to use my functions regardless of the point type. I read the “Writing a new PCL class” tutorial but I have not got it. I will share the simplest class where I am trying to use this technique. Its only function is to create the KDtree of a pointcloud in the correct point of the execution of a parent tree of processes.
KdtreeBuilder_Process.h
#ifndef KDTREEBUILDER_PROCESS_H
#define KDTREEBUILDER_PROCESS_H
#include "ProcessManager/ProcessConcurrent.h" //Parent class
#include <pcl/kdtree/kdtree_flann.h>
class KdtreeBuilder_Process:public ProcessConcurrent
{
public:
KdtreeBuilder_Process(pcl::PointCloud<pcl::PointXYZ>::Ptr inputCloud,pcl::KdTree<pcl::PointXYZ>::Ptr cloudKdtree);
virtual void run(); //method that executed when the process starts
private:
pcl::PointCloud<pcl::PointXYZ>::Ptr mInputCloud;
pcl::KdTree<pcl::PointXYZ>::Ptr mCloudKdtree;
};
#endif // KDTREEBUILDER_PROCESS_H
KdtreeBuilder_Process.cpp
#include "KdtreeBuilder_Process.h"
KdtreeBuilder_Process::KdtreeBuilder_Process(pcl::PointCloud<pcl::PointXYZ>::Ptr inputCloud,pcl::KdTree<pcl::PointXYZ>::Ptr cloudKdtree):
mInputCloud(inputCloud),mCloudKdtree(cloudKdtree)
{
}
void KdtreeBuilder_Process::run(){
mCloudKdtree->setInputCloud(mInputCloud);
}
My intention is to be able to use this class with any point type that contains XYZ coordinates
Thanks for your support.
BR
First of all when dealing with templates you have to accept that all implementation will need to be moved to header files. If you want KdtreeBuilder_Process to be a template that takes class of point in parameter you just need to add appropriate template declaration syntax:
template<class PointType>
class KdtreeBuilder_Process:public ProcessConcurrent
{
public:
If PointCloud class is ready to accept all classes with XYZ coordinates you just need to change your code accordingly
KdtreeBuilder_Process(pcl::PointCloud<PointType>::Ptr inputCloud,pcl::KdTree<PointType>::Ptr cloudKdtree): mInputCloud(inputCloud), mCloudKdtree(cloudKdtree) { }
virtual void run(){
mCloudKdtree->setInputCloud(mInputCloud);
}
private:
pcl::PointCloud<PointType>::Ptr mInputCloud;
pcl::KdTree<PointType>::Ptr mCloudKdtree;
};
Good luck!
I solve the issue. Here is the final solution using only header file:
KdtreeBuilder_Process.h
#ifndef KDTREEBUILDER_PROCESS_H
#define KDTREEBUILDER_PROCESS_H
#include "ProcessManager/ProcessConcurrent.h"
#include "PointDefinitions.h"
#include <pcl/kdtree/kdtree_flann.h>
#include <QDebug>
template<class PointType>
class KdtreeBuilder_Process:public ProcessConcurrent
{
typedef typename pcl::PointCloud<PointType>::Ptr PointCloudPtr;
typedef typename pcl::KdTree<PointType>::Ptr KdTreePtr;
public:
KdtreeBuilder_Process(PointCloudPtr inputCloud,KdTreePtr cloudKdtree): mInputCloud(inputCloud), mCloudKdtree(cloudKdtree) { }
virtual void run(){
mCloudKdtree->setInputCloud(mInputCloud);
}
private:
PointCloudPtr mInputCloud;
KdTreePtr mCloudKdtree;
};
#endif // KDTREEBUILDER_PROCESS_H

template class with functions that do not use the template

I am jumping through hoops to reduce inheritance.
I read one similar question here. It shows how the issue can be resolved using a base class. I try to loose inheritance, so I am looking for something different - more along the lines of annotation.
I create and compile a template class with one specialisation (normal). The method that requires the template is in the header (Mixer.hpp). The method that does not require the template is in the cpp file (Mixer.cpp). When compiled into a static library, the cpp part only gets compiled as one specialisation (Mixer<normal>). The compiler does not know about (awsome) at that time. Importing the resulting static library into another project and attempting to create a different generic (awsome) class results in a linker error because obviously the library does not contain that method identifier (Mixer<awesome>::noTemplateInvolved). However the code for the normal implementation is as good as any so really the linker could just link to the existing source of the other template version (Mixer<?dontcare?>::noTemplateInvolved). All that the compiler has to do is to mark it appropriately for the linker.
Here is source code that results in a linker error:
//Target compiled to Provider.lib
//Mixer.hpp
#pragma once
#include <iostream>
using namespace std;
struct normal { static void log() { cout << "normal\n"; } };
template<typename output = normal>
class Mixer
{
public:
void callingTemplate();
void noTemplateInvolved();
};
template<typename output>
void Mixer<output>::callingTemplate() { output::log(); }
//Mixer.cpp
#include "Mixer.hpp"
void Mixer<>::noTemplateInvolved()
{
cout << "noTemplateInvolved\n";
}
//Target Compiled to User.exe
//This target imports Provider.lib
#include <Provider\Mixer.hpp>
#pragma comment(lib, "Provider.lib")
struct awsome { static void log() { cout << "awsome\n"; } };
int main()
{
Mixer<> n;
n.callingTemplate();
n.noTemplateInvolved();
Mixer<awsome> a;
a.callingTemplate();
a.noTemplateInvolved(); //linker error here
return 0;
}
The class Mixer<awsome> can link to the method callingTemplate because its definition is in the header and the compiler creates that function. At User.exe compile time the definition of noTemplateInvolved is hidden from the compiler. The compiler can not create that method and linking has to fail.
There are three solutions that I am aware of.
move the definition of noTemplateInvolved to the header.
include the cpp file
inherit from a baseclass
I am looking for another solution. The body of noTemplateInvolved really has nothing to do with the template. I would like to annotate the method in the header. I want the compiler to know it should always use the same base implementation regardless of the template.
Is that at all possible?
EDIT: Annotated that boring paragraph at the beginning a bit.
The answer turns out to be a base class as suggested in the comments. One of the reasons I wanted a base class is that I did not want to refactor. Refactoring using a base class is actually really simple.
Rename the original class to original_base.
Inherit from original_template inherits from original_base. Make sure to copy the contructor and pass through all the arguments to the base class.
The statement using original = original_template<your default case here> ensures that no other source code has to be modified just yet.
Applied to the example above I ended up doing something like this:
//Target compiled to Provider.lib
//Mixer.hpp
#pragma once
#include <iostream>
using namespace std;
struct normal { static void log() { cout << "normal\n"; } };
class Mixer_Base
{
private:
int mixcount;
public:
Mixer_Base(int count);
void noTemplateInvolved();
};
template<typename output = normal>
class Mixer_tempalte : public Mixer_Base
{
public:
Mixer_tempalte(int count) : Mixer_Base(count)
{}
void callingTemplate();
};
template<typename output>
void Mixer_tempalte<output>::callingTemplate()
{
output::log();
}
using Mixer = Mixer_tempalte<>;
//Mixer.cpp
#include "Mixer.hpp"
void Mixer_Base::noTemplateInvolved()
{
cout << "noTemplateInvolved\n";
}
Mixer_Base::Mixer_Base(int count) : mixcount(count)
{}
//Target Compiled to User.exe
//This target imports Provider.lib
#include <Provider\Mixer.hpp>
#pragma comment(lib, "Provider.lib")
struct awsome { static void log() { cout << "awsome\n"; } };
int main()
{
Mixer n(4);
n.callingTemplate();
n.noTemplateInvolved();
Mixer_tempalte<awsome> a(3);
a.callingTemplate();
a.noTemplateInvolved();
return 0;
}
In a way an annotation feels just like the base class feels. Everything in the base class is now annotated the way I wanted it to be, though this does not reduce inheritance.

C++: Class method using function defined in main

So I have a class:
class MyClass
public:
printSomeStuff() { //Including implementation here to save space
print(data);
}
private:
int data;
And a main program, with a template function defined outside:
template<typename T>
void print(T val) {
cout << val;
}
int main() {
MyClass a;
a.printSomeStuff();
}
The idea is that I could move MyClass somewhere else and be fine, but a new print function would need to be defined based on the scenario. Typically this would just be a cout.
If I try to actually use this style of coding, though, I get an error because print is not defined in MyClass.cpp.
How should I address this issue?
You should move your print() function into a header (and a suitable namespace) and include it into the translation units where it is needed, e.g.:
// print.h
#ifndef INCLUDED_PRINT
#define INCLUDED_PRINT
#include <iostream>
namespace utilities {
template <typename T>
void print(T const& val) {
std::cout << val;
}
}
#endif
You'd then include this header into the translation where it is used, e.g.
// MyClass.h
#ifndef INCLUDED_MYCLASS
#define INCLUDED_MYCLASS
#include "print.h"
class MyClass
public:
printSomeStuff() { //Including implementation here to save space
utilities::print(data);
}
private:
int data;
};
#endif
Put your template definition in its own header file and include it in your class implementation file.
That said, with something as trivial as printing, it may be must as easy to do it in the printSomeStuff method entirely. The extra indirection isn't really buying you anything.
The header in which print template is defined has to be accessible from the header in which MyClass is defined, but not necessarily from main, so you could move it to a separated header and include it from MyClass.hpp or even MyClass.cc

templates - undefined reference error

I have the following simple template code:
#ifndef CLUSTER_H
#define CLUSTER_H
#include <iostream>
#include <vector>
template <typename T, size_t K>
class Cluster
{
public:
void Print() const;
private:
std::vector<T> objects;
};
template <typename T, size_t K>
void Cluster<T,K>::Print() const
{
for (int i=0; i<objects.size(); i++)
{
T curr=objects[i];
std::cout << curr << " ";
}
std::cout << std::endl;
}
#endif
and for some reason I get the following error: "undefined reference to 'Cluster<int, 5u>::Print() const'. What could be the cause for this?
Thanks!
So, I'm going to go out on a limb here and say that you've defined a template function in a CPP file, which means it will end up in a different translation unit. Here's a simple example:
A header, example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
template<int TValue>
class example
{
public:
int get_tvalue();
};
#endif
A source file, example.cpp
#include "example.h"
template<int TValue>
int example<TValue>::get_tvalue()
{
return TValue;
}
And another source file, main.cpp
#include "example.h"
int main()
{
example<5> instance;
instance.get_tvalue();
return 0;
}
If I compile these together using GCC, I get undefined reference to 'example<5>::get_tvalue()'. This is because of the way template classes are instantiated. A template class definition is just that... a template, not an actual class. The actual class definition is created when a parameterised (or specifically, fully specialised) definition of that class occurs, in this case, example<5>. That fully specialised class definition only exists in main.cpp... there's no such class inside example.cpp! Example.cpp contains only the template, and no specialisations. This means the function, get_tvalue is not defined for example<5> in main.cpp, hence the error.
You can fix this in one of two ways. The first way is to always have your entire template class defined in its header file. This is the way its done with STL containers, for example. The alternative is to force creation of a parameterised class in example.cpp... you can do this by adding
template class example<5>;
to the end of example.cpp. Because there's now an actual class definition for example<5> in example.cpp, you will also get an actual function definition for example<5>::get_tvalue and when your translation units main.o and example.o are linked together at the end of the compilation step everything will be fine.
Obviously, this would be a poor approach in most cases, but under circumstances where your template parameters take only a small range of values it can work. Putting your whole class in the header file is probably easiest, safest and most flexible though.