undefined reference to `std::ostream& SpyOutput::operator<< <double>(double const&)' - c++

I'm trying to intercept "the data" from standard output (for this question I'm working with cout). Also for this question I'm working with double, but the program should be able to handle any primitive data type. When I try to compile my code I get this error:
undefined reference to `std::ostream& SpyOutput::operator<<
(double const&)' collect2: error: ld returned 1 exit status
this is my main:
#include "SpyOutput.h"
#define endl '\n'
int main ( int argc, char *argv[], char *env[] ) {
double d1 = 12.3;
SpyOutput spy(&cout);
spy << d1;
return 0;
}
this is my header file:
#include <iostream>
using namespace std;
class SpyOutput {
private:
ostream* output;
public:
SpyOutput(ostream* os);
template <class T>
ostream &operator<<(const T &x);
};
this is my implementation file:
#include "SpyOutput.h"
SpyOutput::SpyOutput(ostream* os){
output = os;
}
template <class T>
ostream& SpyOutput::operator<<(const T &x){
// SOME CODE GO HERE
return *output;
}
I have googled this error (and similar) without finding a working solution, thanks in advance for any help or hint that you can provide to me! :-)

What's the problem?
For an explanation why it doesn't compile, see "Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?"
As an example, consider the header file foo.h which contains the following template function declaration:
// File "foo.h"
template<typename T>
void foo();
Now suppose file foo.cpp actually defines that template function:
// File "foo.cpp"
#include <iostream>
#include "foo.h"
template<typename T>
void foo()
{
std::cout << "Here I am!\n";
}
Suppose file main.cpp uses this template function by calling foo():
// File "main.cpp"
#include "foo.h"
int main() { foo<int>(); ... }
If you compile and link these two .cpp files, most compilers will generate linker errors. Because in order for the compiler to generate the code, it must see both the template definition (not just declaration) and the specific types/whatever used to "fill in" the template. If the template body is defined in the .cpp the compiler won't see it and hence won't generate any code for it.
How to fix it?
There is more than one possible solution around this issue. I suggest moving the definition of the template function into the .h file.
// File "foo.h"
template<typename T>
void foo()
{
std::cout << "Here I am!\n";
}
In your source you can call it as usual:
// File "main.cpp"
#include "foo.h"
int main() { foo<int>(); ... }

You need to place your template implementation of SpyOutput::operator<< into the header file

Related

Is this the correct way to compile if I am using explicit instantiation?

For maintainability reasons, I need to split the declaration and the definition of a template class. I want to know what is the correct way to compile the file if I'm using this design choice.
So, as a minimal reproducible example (using templated function just to be more compact) consider:
Header file foo.hpp where I declare a templated function myfun
//file foo.hpp
#ifndef foo_hpp
#define foo_hpp
template <typename T>
void myfun();
#endif /* foo_hpp */
Source file foo.cpp file where I define the function myfun
//file foo.cpp
#include "foo.hpp"
#include <iostream>
template <typename T>
void myfun(){
std::cout << "Call to myfunc \n";
}
template void myfun<int>();
Finally, the main.cpp file that uses myfun<int>
#include "foo.hpp"
int main(){
myfun<int>();
return 0;
}
I would compile and generate the executable test from command line just by doing:
g++ -o test foo.cpp main.cpp
because in this way the linker is able to see the instantiation of myfun<int>.
Is this the correct way to compile ?
EDIT:
Another possibility is to use a `.tpp file
//file foo.tpp
#include "foo.hpp"
#include <iostream>
template <typename T>
void myfun(){
std::cout << "Call to myfunc \n";
}
and put it into the .hpp file
//file foo.hpp
#ifndef foo_hpp
#define foo_hpp
template <typename T>
void myfun();
#include "foo.tpp"
#endif /* foo_hpp */
Finally, the main.cpp file that uses myfun<int>
#include "foo.hpp"
int main(){
myfun<int>();
return 0;
}
Now, I compile just by doing:
g++ -o test main.cpp
This works, but as I include the .tpp (which includes the header) into the header, it seems I am including the header into itself, and it's pretty weird

What would be the reason that the explicit instantiation failed?

/* MyClass.h */
class MyClass
{
public:
template <typename T>
void Foo(const T &val);
};
/* MyClass.cpp */
#include <string>
#include <iostream>
#define EXPLICIT_INSTANTIATION_FOO(MyType) \
template void MyClass::Foo(const MyType &val)
EXPLICIT_INSTANTIATION_FOO(int);
EXPLICIT_INSTANTIATION_FOO(float);
EXPLICIT_INSTANTIATION_FOO(std::string);
template <typename T>
void MyClass::Foo(const T &val)
{
std::cout << "My Value: " << val << std::endl;
}
For some other reason, I couldn't define the Foo in the header file, then I try to explicitly instantiate all the types I need in the source file. And it works pretty well on g++-4.8.
Then once it I submit the codes, I find the building failed on Windows 10, x86_64, cl19. It was an unresolved symbol error there and was look like my instantiations weren't be exposed from the object.
But interestingly, when I try to reproduce this error on my own Windows by making that simple snippet above. I found it works well on my vs2017 with cl19...
There would be thousands of configuration differs between the company and the personal machine, but I just don't have any idea that what would be the reason why the instantiations don't work there... Any ideas appreciated! :)
SUPPLEMENTS:
FYI, the complete codes are here:
/* MyClass.h */
#pragma once
class MyClass
{
public:
MyClass();
~MyClass();
template <typename T>
void Foo(const T &val);
};
/* MyClass.cpp */
#include "MyClass.h"
#include <iostream>
#include <string>
#define EXPLICIT_INSTANTIATION_FOO(MyType) \
template void MyClass::Foo(const MyType &val)
EXPLICIT_INSTANTIATION_FOO(int);
EXPLICIT_INSTANTIATION_FOO(float);
EXPLICIT_INSTANTIATION_FOO(std::string);
MyClass::MyClass() {}
MyClass::~MyClass() {}
template <typename T>
void MyClass::Foo(const T &val)
{
std::cout << "My Value: " << val << std::endl;
}
/* main.cpp */
#include "MyClass.h"
#include <iostream>
#include <string>
int main()
{
std::string v = "hello";
MyClass cls;
cls.Foo(v);
std::cin.get();
return 0;
}
Which passed the compilation on msvc.
Move the function definition to before the EXPLICIT_INSTANTIATION_FOO invocations. This is something that never should have worked but compilersllowed, they are slowly coming around on it. If you want to make msvc reject it use the /permissive- flag.
Thanks, everybody, this silly question is solved.
The reason is the template instantiations will not inherit the dllexport attribute from the template definition on Windows. And obviously, it works on my silly test codes because it wasn't compiled as the DLL :)

Undefined reference to Classname::Classname() and other errors

This is a noob question, sorry, I'm coming from Java and have no idea why my OO stuff isn't working. I have this main:
#include <iostream>
#include "Foo.h" //changed name
using namespace std;
int main(int argc, char*argv[])
{
int choice;
cin >> choice;
Foo net;
switch(choice)
{
case 1: net.buildNetwork(); break;
}
}
This Foo.h file:
#ifndef FOO_H
#define FOO_H
#include <iostream>
struct City{
std::string cityName;
std::string message;
City *next;
City(){}; // default constructor
City(std::string initName, City *initNext, std::string initMessage)
{
cityName = initName;
next = initNext;
message = initMessage;
}
};
class Foo
{
public:
Foo();
~Foo();
void addCity(std::string, std::string);
void buildNetwork();
void transmitMsg(char *); //this is like a string
void printNetwork();
protected:
private:
City *head;
City *tail;
};
#endif // FOO_H
And this Foo.cpp file, all in the same directory:
#include "Foo.h"
#include <iostream>
using namespace std;
Foo::Foo()
{
head = tail = NULL;
}
Foo::~Foo(){}
void Foo::buildNetwork()
{
cout << "works" << endl;
}
void Foo::transmitMsg(){}
void Foo::printNetwork(){}
void Foo::addCity(){}
When I compile, I get
/tmp/ccNx3fY5.o: In function `main':
main.cpp:(.text+0x38): undefined reference to `Foo::Foo()'
main.cpp:(.text+0x4c): undefined reference to `Foo::buildNetwork()'
main.cpp:(.text+0x59): undefined reference to `Foo::~Foo()'
main.cpp:(.text+0x7e): undefined reference to `Foo::~Foo()'
collect2: error: ld returned 1 exit status
What's wrong? Also, another question: in Foo.cpp, why do I need Foo::Foo() etc? I used namespace std, so why can't I just say Foo()?
Looking at the way you compile, you are only providing only one source file (main.cpp) whereas the correct way is to specify all the source files. In your case, it would be:
g++ main.cpp foo.cpp -o executable
The "undefined reference" error is a error thrown at the linking stage when the linker can't resolve the names correctly because, you didn't link the source files properly like above.
Additionally, make sure that when you declare a function prototype, the implementation of the function should also have the same signature. In your example, you provided the function prototypes as:
void transmitMsg(char *);
void addCity(std::string, std::string);
But your implementation of those functions don't have the correct signature. They should have been:
void Foo::transmitMsg(char *){}
void Foo::addCity(std::string, std::string){}
why do I need Foo::Foo() etc?
Because Foo() is a function of the class Foo.
I used namespace std, so why can't I just say Foo()?
When you make a call to using namespace ; all symbols in that namespace will become visible without adding the namespace prefix. A symbol may be for instance a function, class or a variable.
Foo is not a namespace like "std". It is a user-defined class.
Also, another question: in Foo.cpp, why do I need Foo::Foo() etc? I
used namespace std, so why can't I just say Foo()?
You need to write Foo::Foo() in foo.cpp because you are defining the constructor outside the body of the Foo class which is present in foo.h.
std is the standard namespace and using that in no way absolves you from referring to the Foo class you have created since its not a part of the standard namespace
You have not included foo.cpp in your compile command, So this is why you cant link the functions. You need to use the command line argument:
g++ main.cpp foo.cpp -o main
This allows the compiler to find the functions in foo.cpp.

The strange behaviour when using c++ specialization template

I am newbie in programming with c++ template. I have 3 code files
main.cpp
#include "template_test.h"
#include <iostream>
using namespace std;
int main()
{
mytest<int> mt;
mt.method(1);
system("pause");
return 0;
}
template_test.h
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
template<>
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
template_test.cpp
#include "template_test.h"
//empty
The code takes effective in VS2013. However when I change my code to 2 sitiuations, there are both something wrong with my code.
1.The first is with the linker error code.
main.cpp
#include "template_test.h"
#include <iostream>
using namespace std;
int main()
{
mytest<int> mt;
mt.method(1);
system("pause");
return 0;
}
template_test.h
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input);
};
template<class T>
void mytest<T>::method(T input)
{
cout << " " << endl;
}//explicit specialization here
template<>
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
template_test.cpp
#include "template_test.h"
//empty
2.The second output nothing instead of the correct answer 'ok'.
main.cpp
#include "template_test.h"
#include <iostream>
using namespace std;
int main()
{
mytest<int> mt;
mt.method(1);
system("pause");
return 0;
}
template_test.h
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
template_test.cpp
#include "template_test.h"
template<>
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}//move from .h to .cpp file here
The strange behaviour of c++ template makes me confused. So, what's the problem?
The first problem is caused by the fact that your explicit specialization
template<>
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
is defined in the header file and outside the class definition and without the keyword inline.
An explicit specialization causes an actual function (rather than a mere template) to be defined. That definition will occur in every translation unit, so if you compile template_test.cpp and main.cpp separately, the definition of the function will be included in both object files, causing a multiple-definition error at linking time (because it's a violation of the ODR, the one-definition-rule).
You best avoid this either by including the function definition inside the class template definition (by specializing the entire class template for int), or using the keyword inline:
template<>
inline void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
The second problem is caused by the fact that a template specialization must always be declared before it is used:
(14.7.3/6) If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined. [...]
Since your main.cpp includes the header file, but not the .cpp file, the declaration of the template specialization is not known when it is used in main.cpp. You solve this best by including the specialization in the header file, either inside the class template definition (by specializing the entire class template for int), or using the keyword inline outside the class template definition.
You second question first. Remember a rule when using template. Do not separate the template implementation to a cpp file. Make them all in one .h file.
You first code compiles fine in my VC2012, I am not sure what's wrong with VC2013.

Can't seem to include any cpp file other than main.cpp when using template class

I decided to cut the necessary code down to the bare minimum needed to display this error. I have an STL list wrapper template class that exists in hc_list.h file. The entire code is below:
// hc_list.h file
#ifndef HC_LIST_H
#define HC_LIST_H
#include <cstdlib>
#include <list>
template <typename T>
class hcList
{
private:
std::list<T> selfList ; // a single internal STL list to hold the values
public:
hcList(void) {} ;
~hcList(void){} ;
// The error occurs on the line below
template <typename U> friend std::ostream& operator<<(std::ostream &, const hcList<U> &) ;
} ;
#endif // HC_LIST_H
This code is included in the main.cpp file, where the main function is below:
// main.cpp file
#include <iostream>
#include "hc_list.h"
int main()
{
std::cout << "Begin Test" << std::endl;
return 0;
}
This code, when entered into a CodeBlocks project will compile as is with 0 errors or warnings. However, then I include another cpp file and attempt to include the list header, like the following:
// anyNamedFile.cpp file
#include "hc_list.h"
When I include any cpp file into the project, I get a compiler error:
error: expected initializer before '&' token
I do not understand what I am doing wrong, and could really use some help.
Your header file uses std::ostream, (just before an &) but does not include any header which might declare it.
Try adding
#include <iosfwd>
in your header.