This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 8 years ago.
Can someone please explain to me why the following won't compile?, and hopefully the obvious thing that I have missed...
functions.hpp:
template<typename T> string vector_tostr(std::vector<T> v);
functions.cpp:
template<typename T> string vector_tostr(std::vector<T> v){
std::stringstream ss;
std::string thestring = "";
if(v.size() > 0){
ss << "[";
for(size_t i = 0; i < v.size(); i++){
if(i != 0)
ss << " ";
ss << v[i];
}
ss << "]";
thestring = ss.str();
}
return thestring;
}
main.cpp
#include "functions.hpp"
int main(int argc, char *argv[]){
vector<int> thevector;
thevector.push_back(1);
thevector.push_back(2);
string result = vector_tostr(thevector);
//I have also tried vector_tostr<int>(thevector)
}
The cryptic error I am getting as follows:
Undefined symbols for architecture x86_64: "std::basic_string, std::allocator >
vector_tostr(std::vector >)", referenced
from:
_main in main.o ld: symbol(s) not found for architecture x86_64 collect2: error: ld returned 1 exit status make: * [main] Error 1
You are not allowed to seperate the declaration and definition of a templated function in the same way that you would a normal function (declaration in '.hpp' file, definition in '.cpp' file). There are a couple of ways you can get around that.
You can declare AND define the function in the same place in the header file.
OR
You could try this, in a file called functions.inl:
template<typename T>
inline string vector_tostr(std::vector<T> v){
std::stringstream ss;
std::string thestring = "";
if(v.size() > 0){
ss << "[";
for(size_t i = 0; i < v.size(); i++){
if(i != 0)
ss << " ";
ss << v[i];
}
ss << "]";
thestring = ss.str();
}
return thestring;
}
Then, at the end of the header file (functions.hpp), type this in:
#include "functions.inl"
.inl is the file extension for the inline header file. You can use this to seperate the declaration
and definition of templated functions.
Templates are instantiated in compile time. What the compiler does is create one overloaded method for each template argument value that is used in the code. For example, using int and double as template argument will create two overloaded methods from the same definition, only vary in argument type. So compiler must be able to see the definition while compiling. You can do this in several ways
Fully defined in header
Defined in for ex. .impl file and include it in the declaring header
Explicitly instantiated with template parameter in a .cpp file, in that case only the instantiated versions can be used.
You need to have the implementation of the function template visible where it's used. Otherwise, the compiler doesn't know how to instantiate the function given a type.
Put the function definition in functions.hpp. There is no use of functions.cpp.
Related
This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 2 years ago.
I'm having some difficulty reproducing an example program of Object-Oriented Programming Using C++ described in "Encapsulation and Type Extensibility."
For simplicity's sake, I've cut out most of the code to focus on the specific error at hand:
#include <iostream> // Access standard IO library
#include <string> //Access type 'string'
using namespace std; //Use standard library namespace
const int max_length = 255;
class my_string {
public:
void assign(const char* st);
int length() const { return len; }
void print() const
{ cout << s << "\nLength: " << len << endl; }
private:
char s[max_length];
int len;
};
int main()
{
my_string one;
one.assign("I'm sorry Dave, I'm afraid I can't do that.");
one.print();
system("PAUSE");
}
When I try to compile, I get the error message:
[Linker error] undefined reference to 'my_string::assign(char const*)'
I'm not sure what I'm doing wrong. My best guess is that assign is incorrectly defined, since the main() block seems fine.
Edit:
The complete example as written in the book is:
In file string1.cpp
const int max_len = 255;
class my_string {
public:
void assign(const char* st);
int length() const { return len; }
void print() const
{ cout << s << "\nLength: " << len << endl; }
private:
char s[max_length];
int len;
};
int main()
{
my_string one, two;
char three[40] = {"My name is Charles Babbage."};
one.assign("My name is Alan Turing.");
two.assign(three);
cout << three;
cout << "\nLength: " << strlen(three) << endl;
if (one.length() <= two.length())
one.print();
else
two.print();
}
Linking and compiling errors are two different things. A compiler error means that you did something wrong in the syntax.
A linking error tells you that there is a part missing when the linker tries to put your program together.
[Linker error] undefined reference to 'my_string::assign(char const*)'
This error tells you that somewhere the promise was made to the compiler that my_string::assign(char const*) exists and can be used (by a declaration void assign(const char* st);). But in the linking step the linker cannot find that function.
If the error references a function that you have written, then you might have forgotten the definition of it or have mismatching signature between declaration and definition.
The compiler can't find it's definition.
Usually there is a header file (.h) where the class' declaration is put, including as less as possible and a source file (.cpp) that includes all the definitions.
The header file declarations tells the compiler which methods shall be available (as a promise),
the source file should contain the definition of the functions that are declared in the header file.
If they aren't defined, meaning there is no body for that function, it can't be executed. In your book, the code is both declared and defined, by writing the methods inside the class' definition.
You could do the same:
public:
void assign(const char* st) {
/* implementations of the assign method here
(or leave it empty for this example, but rather don't)*/
};
int length() const { return len; };
...
This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 6 years ago.
I am making a program with a list of baby names but I've decided to make a seperate function to open the file, this is what I have got so far.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void open_file(ifstream& in, char fileName[]);
void find_name(ifstream& in, string name, int numNames);
int main() {
const int NUMNAMES = 1000;
ifstream inStream;
char fileName[30];
string name;
cout << "Enter the name of the file that contains the names: " << endl;
open_file(inStream, fileName);
cout << "Enter the name to search for (capitalize first letter): " << endl;
cin >> name;
find_name(inStream, name, NUMNAMES);
inStream.close();
}
void open_file(ifstream& ) {
string line;
ifstream myfile ("babyNames.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
cout << line << '\n';
}
myfile.close();
}
else cout << "I/O failure opening file babyNames";
}
Does anyone know why I am getting so many error messages:
Undefined symbols for architecture x86_64:
"find_name(std::__1::basic_ifstream<char, std::__1::char_traits<char> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, int)", referenced from:
_main in Untitled-1b6d2e.o
"open_file(std::__1::basic_ifstream<char, std::__1::char_traits<char> >&, char*)", referenced from:
_main in Untitled-1b6d2e.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Does anyone know what I am doing wrong, I feel like it is relatively close I'm just fairly new to streams in c++.
The shown code declares and calls the following functions:
void open_file(ifstream& in, char fileName[]);
void find_name(ifstream& in, string name, int numNames);
Unfortunately, the shown code does not define any of these two functions, and the two linking errors are the result of that.
The shown code does define some function that's also called open_file(), but it's a completely different function because it takes different parameters. The shown code does not define any function called find_name().
You cannot simply declare a function like:
void open_file(ifstream& in, char fileName[]);
And then expect the code for this function to automatically appear somewhere. You have to define, and write the contents of this function. The parameters in this function, when you define it, must be the same as what you declared here.
This question already has an answer here:
linker cannot find a C++ static member [duplicate]
(1 answer)
Closed 6 years ago.
I've declared a public static member to keep the total count of the instances of my class. The code is as follows:
class Hello {
public:
static int myCount;
void test(){
//do nothing
};
Hello(){
Hello::myCount += 1;
};
~Hello() {
Hello::myCount -= 1;
}
};
int main(int argc, const char * argv[]) {
// insert code here...
Hello *p1 = new Hello();p1->test();
Hello *p2 = new Hello();p2->test();
cout << Hello::myCount;
return 0;
}
However, I when compile, it says:
Undefined symbols for architecture x86_64:
"Hello::myCount", referenced from:
_main in main.o
Hello::Hello() in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I don't know where I'm wrong. It's been years from the last time I worked with c++, so could you please suggest a solution?
Thank you.
Static members have to be defined outside of the class, e.g.:
class Hello {
public:
static int myCount;
void test(){
//do nothing
};
Hello(){
Hello::myCount += 1;
};
~Hello() {
Hello::myCount -= 1;
}
};
int Hello::myCount = 0; // definition outside of the class
(...)
Here is an example to show, that it helps to solve your problem: http://ideone.com/LVXVCc
It's all because a rule called One Definition Rule.
You can read more about this one in a context of static class members here.
In short: static int myCount declaration is not a definition of a member. Classes are usually placed in their .h/.hpp header files and are included to many other files. If those'd contain static member and lines like the one above would be a definition, it will lead to the multiple-definitions error.
To prevent that, this declaration is not treated as a definition and you must define it yourself later.
I tried compiling a simple program on Xcode and got the following messages:
function<anonymous namespace>::Initialize' has internal linkage but is not defined
function<anonymous namespace>::HandleBadInput' has internal linkage but is not defined
Undefined symbols for architecture x86_64:
"(anonymous namespace)::Initialize()", referenced from:
_main in main.o
"(anonymous namespace)::HandleBadInput()", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
The header file looks like this:
#ifndef WJKErrorHandling
#define WJKErrorHandling
namespace WJKErrorHandling{
void Initialize(void);
int HandleBadInput(void);
}
#endif // defined(WJKErrorHandling)
the implementation file looks like this:
#include <iostream>
#include "WJKErrorHandling.h"
namespace WJKErrorHandling{
void Initialize(void){
std::cin.exceptions(std::cin.failbit);
}
int HandleBadInput(void){
std::cerr << "Input Error: wrong type?\n";
std::cin.clear();
char BadInput[5];
std::cin >> BadInput;
return 1;
}
}
and main.cpp looks like this:
#include <iostream>
#include "WJKErrorHandling.h"
void Prompt (void){
//Prompts the user to begin entering numbers
std::cout << "Begin entering numbers: \n";
}
float GetNumber (void){
std::cout << "Number: \n";
float Number;
std::cin >> Number;
return Number;
}
std::string GetString (void){
std::cout << "String: \n";
std::string String;
std::cin >> String;
return String;
}
int main()
{
Prompt();
WJKErrorHandling::Initialize();
int ReturnCode = 0;
try{
float Number = GetNumber();
std::cout << Number;
std::string String = GetString();
std::cout << String;
std::cout << "SUCCESS!!!!\n";
}
catch(...){
ReturnCode = WJKErrorHandling::HandleBadInput();
}
return ReturnCode;
}
I've tried finding an answer so far, but I haven't understood any of the posts that I've found. I'm new with C++, so any help would be greatly appreciated!
Your #define Guard is causing name lookup issue.
change to below style should fix the issue:
#ifndef WJK_ERROR_HANDLING_H
#define WJK_ERROR_HANDLING_H
You could also use the non-standard but more idiomatic #pragma once, according to its wikipedia page it is supported by all major compilers.
Since many compilers have optimizations to identify include guards, there is no speed advantage between the two. For myself I see the following advantages of #pragma once:
It has only one meaning (whereas defines serve different purposes) and will not clash with other things (e.g. a namespace as in your case).
It is little to type and simple to remember.
You cannot have errors due to a typo (WJKERRORHANDLNG_H, ups and I is missing), because you started the header as a copy of another and forgot to change the include guard, which gives you rather nasty bughunting sessions.
This turns out to be a bad include guard:
#ifndef WJKErrorHandling
#define WJKErrorHandling
because you later try to use WJKErrorHandling as a namespace, but the macro makes it go away.
Change your include guard to something like:
#ifndef WJKERRORHANDLING_H
#define WJKERRORHANDLING_H
which is probably more idiomatic and less likely to conflict with something.
I have 3 C++ files:
genericStack.h:
template <class T>
class Stack{
public:
Stack (int size){
top = -1;
MAX_SIZE = size;
v = new T (size);
}
~Stack(){ delete v;}
T pop();
void push (T);
class Underflow{};
class Overflow{};
private:
int top;
int MAX_SIZE;
T* v;
};
genericStackImpl.c++:
#include "genericStack.h"
template <class T>
void Stack <T> :: push (T c){
if (top == MAX_SIZE - 1) throw Overflow();
v[++top] = c;
}
template <class T>
T Stack <T> :: pop(){
if (top < 0) throw Underflow();
return v[top--];
}
driver.c++:
#include <iostream>
#include "genericStack.h"
int main(){
Stack<char> sc(3);
try{
while (true) sc.push ('p');
}
catch (Stack<char>::Overflow){std::cout << "Overflow caught\n";}
try{
while (true) std::cout << sc.pop() << '\n';
}
catch (Stack<char>::Underflow){ std::cout << "Underflow caught\n";}
return 0;
}
When i compile using g++ 4.5:
g++ -o driver driver.c++ genericStackImpl.c++
I get these errors:
/tmp/ccLXRXgF.o: In function `main':
driver.c++:(.text+0x2e): undefined reference to `Stack<char>::push(char)'
driver.c++:(.text+0x3c): undefined reference to `Stack<char>::pop()'
collect2: ld returned 1 exit status
I dont understand what the problem is. If i move the implementation in the driver file, then it compiles and runs.
Generally speaking, template definitions need to also be in the header file. An exception to this is when you are explicitly instantiating, or using explicit specialisations, neither of which you are doing.
One way to solve this would be to move the contents of genericStackImpl.c++ to the bottom of its header file.
The reason for this is because template functions are not actual functions, they are just templates. A template is used (instantiated) to create actual functions, and those are what you link against.
There are no functions in genericStackImpl.c++. The functions only get created once you use them, i.e. the first time the compiler sees sc.push and sc.pop. Unfortunately, when driver.c++ tries to create these functions, it can't find the template bodies -- they hidden in genericStackImpl.c++! Instead, it just compiles a reference to those functions, hoping that some other file will make them.
Finally, when it comes to link time, the linker can't find the function anywhere, so it gives you an error.
Another way to solve this would be to explicitly instantiate those functions yourself in genericStackImpl.c++, i.e.
template class Stack<char>;
This will create the functions, and the linker will find them.
The problem with this approach is that it require you to know what types your going to be using in your stack beforehand, so most people just put template definitions in the header file.