C++: Class method using function defined in main - c++

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

Related

How to use a dllexport-ed class which is derived from an explicitly instantiated template in a dll without warnings?

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?
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.

Method not found: Templates, Virtual Methods, Inheritence, Polymorphism

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.

undefined reference to <std::string>std::string& [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why do I get “unresolved external symbol” errors when using templates?
“undefined reference” to a template class function
I got error on line: Console::getInstance()->readObjectData(a); in main.cpp
undefined reference to void Console::readObjectData<std::string>std::string&)
Console.h
http://pastebin.com/WsQR7JNq
#define CONSOLE_H
#include <string>
using namespace std;
class Console
{
public:
static Console* getInstance();
template <typename T>
void readObjectData(T& o);
protected:
private:
Console(); // Private so that it can not be called
Console(Console const&); // copy constructor is private
Console& operator=(Console const&); // assignment operator is private
static Console* m_pInstance;
};
#endif // CONSOLE_H
Console.cpp
http://pastebin.com/N02HjgBw
#include "Console.h"
#include "Log.h"
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
// Global static pointer used to ensure a single instance of the class.
Console* Console::m_pInstance = NULL;
Console::Console()
{
}
Console::Console(Console const&)
{
}
Console& Console::operator=(Console const&)
{
}
Console* Console::getInstance()
{
if (!m_pInstance) // Only allow one instance of class to be generated.
m_pInstance = new Console;
return m_pInstance;
}
template <typename T>
void Console::readObjectData(T& o) {
//cin >> o;
}
main.cpp
http://pastebin.com/U6qAJUN1
#include "Console.h"
using namespace std;
int main()
{
string a;
Console::getInstance()->readObjectData(a);
return 0;
}
any ideas?
You cannot define template<>'d function in .cpp file.
Move
template <typename T>
void Console::readObjectData(T& o) {
//cin >> o;
}
To header file.
You did not implemented this method. You have to provide implementation for your template in .h file
Because you've not put the implementation of readObjectData in the header, you will need to provide an explicit specialization of the function - one that takes std::string&.
This should go in Console.cpp:
template <>
void Console::readObjectData(string& o) {
//cin >> o;
}
You cannot place your template method implementation in Console.cpp it must appear in the header file, or you must implement an explicit specialization for std::string.
The definition for the templated function (readObjectData) has to be inlined, not in a .cpp file.
The compiler when it see's a class with a templated function, or a templated class, makes a copy of the entire class with the new type stuck in there. So if you stick the definition of the function in the .cpp file, the compiler will not know where the implementation is because it doesn't exist.
In the process of converting some C++ files to the output( executive, shared library or ... ) 2 tools will co-operate, first compiler that create object files and then linker that convert those objects to the output. What you should know is that linker has nothing to do with template( except in special case of explicit instantiation ), and templates will be instantiated by compiler and another note is compiler work with each source files and headers that included in that source file and ignore all other files of your project. So when compiler want to compile main.cpp it see no implementation of readObjectData and thus it can't generate any code in the object files for that function, and when linker want to link objects to result it will never find an implementation for that function! So the easiest way is to move your implementation of readObjectData to the .h file and every thing will work as expected.

C++: Combining private global variables and templates

Suppose there is a global variable in a translation unit. It is constant, but not compile time constant (it is initialized with an object that has a non constexpr constructor). It is declared static since it should be private to the translation unit. Obviously, that global is defined in the .cpp file. However, now I have added a method template to that file that needs the global variable. Since it is a method that will be used by other translation units, it has to be put into the header. However, once it is in the header it can no longer access the global variable. What is the best practice to solve this problem?
There is, but a little tricky way to achieve your goals:
The variable is private, available only to some elements.
Your function template can access it.
Use private static variable in a class defined in header, and make your function/class templates friend of this class.
YourFile.h
class PrivateYourFileEntities {
private:
static const int SomeVariable;
// ... other variables and functions
template <class T>
friend class A;
template <class T>
friend void func();
// the rest of friends follows
};
template <class T>
void A<T>::func() {
int a = PrivateYourFileEntities::SomeVariable;
}
template <class T>
void func() {
int a = PrivateYourFileEntities::SomeVariable;
}
YourFile.cpp
const int PrivateYourFileEntities::SomeVariable = 7;
Put the method declaration into .h file and method body into .cpp file like:
.h file:
#include <iostream>
void myfunc1();
void myfunc2();
.cpp file:
#include "myheader.h"
static int myglobalvar=90;
void myfunc1()
{
cout << myglobalvar << endl;
}
void myfunc2()
{
cout << "Oh yeah" << endl;
}

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.