I'm relatively new to C & C++ and stuck at compiling (or should I say linking) for the whole 2 days. Anyone gives me an idea would be appreciated.
Error message and 3 code files are below. These are what I cut down to minimum from I'm actually working on so that you guys can take a better glimpse at.
Env: Ubuntu 10.10, Eclipse Indigo CDT, g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5
Error message:
**** Build of configuration Debug for project SceneRec2 ****
make all
Building file: ../src/AdaBoost.cpp
Invoking: GCC C++ Compiler
g++ -I"/home/ubuntuLove/Documents/workspace_eclipse/SceneRec2/Includes" -I/usr/src/linux-headers-2.6.35-30/arch/um/include/shared -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/AdaBoost.d" -MT"src/AdaBoost.d" -o "src/AdaBoost.o" "../src/AdaBoost.cpp"
Finished building: ../src/AdaBoost.cpp
Building file: ../src/AdaMain.cpp
Invoking: GCC C++ Compiler
g++ -I"/home/ubuntuLove/Documents/workspace_eclipse/SceneRec2/Includes" -I/usr/src/linux-headers-2.6.35-30/arch/um/include/shared -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/AdaMain.d" -MT"src/AdaMain.d" -o "src/AdaMain.o" "../src/AdaMain.cpp"
../src/AdaMain.cpp: In function ‘int main(int, char**)’:
../src/AdaMain.cpp:6: warning: deprecated conversion from string constant to ‘char*’
Finished building: ../src/AdaMain.cpp
Building target: SceneRec2
Invoking: GCC C++ Linker
g++ -o "SceneRec2" ./src/AdaBoost.o ./src/AdaMain.o
./src/AdaMain.o: In function `main':
/home/ubuntuLove/Documents/workspace_eclipse/SceneRec2/Debug/../src/AdaMain.cpp:5: undefined reference to `AdaBoost<double>::AdaBoost()'
/home/ubuntuLove/Documents/workspace_eclipse/SceneRec2/Debug/../src/AdaMain.cpp:6: undefined reference to `AdaBoost<double>::readFromFile(char*)'
/home/ubuntuLove/Documents/workspace_eclipse/SceneRec2/Debug/../src/AdaMain.cpp:8: undefined reference to `AdaBoost<double>::~AdaBoost()'
/home/ubuntuLove/Documents/workspace_eclipse/SceneRec2/Debug/../src/AdaMain.cpp:8: undefined reference to `AdaBoost<double>::~AdaBoost()'
collect2: ld returned 1 exit status
make: *** [SceneRec2] Error 1
**** Build Finished ****
Note-1. I receive the same result when I execute g++ on terminal.
Note-2. The path of .o files in the argument for linker should be correct (./src/###.o).
AdaBoost.h
#ifndef _ADABOOST_H
#define _ADABOOST_H
#include <iostream>
const double eps = 2.2204e-16;
template<class T>
class AdaBoost
{
int N; //Number of Instances
int D; //Number of Dimensions
int nL; //Number of Learners / Classifiers / Rules
T** fVectors;
int* labels;
void learnRule(int t, double* dist);
double genRule(int t, int* L, double* dist);
public:
//Default Constructor
AdaBoost();
//Constructor
AdaBoost(T** data, int* labels, int n, int d, int nL);
//Train function
void train();
//Test function
void test(double** data, double* pMap);
void test(double** data, double* pMap, int n);
int writeToFile(char* fName);
int readFromFile(char* fName);
//Destructor
~AdaBoost();
};
#endif
AdaBoost.cpp
#include "AdaBoost.h"
#include <fstream>
using namespace std;
template class AdaBoost<double> ;
template<class T>
int AdaBoost<T>::readFromFile(char* fName) {
ifstream inFile;
int temp;
int d, dir;
float thr, wt;
inFile.open(fName);
if (!inFile)
return 0;
inFile >> temp;
this->nL = temp;
int k = 0;
while (!inFile.eof() && k < nL) {
inFile >> d;
inFile >> thr;
inFile >> dir;
inFile >> wt;
k++;
}
inFile.close();
return 1;
}
AdaMain.cpp
#include "AdaBoost.h"
using namespace std;
int main(int argc, char** argv)
{
AdaBoost<double> rdClass;
rdClass.readFromFile("Naerer");
return 0;
}
If you are using explicit instantiation, you have to define the generic version of the member function before instantiating the class:
template<class T>
int AdaBoost<T>::readFromFile(char* fName) {
// ...
}
template class AdaBoost<double>;
However, if you don't have a specific or pressing reason to use explicit instantiation in the first place, go with the other recommendations and define the templates in the header.
You cannot separate template class definition and implementation in different compilation units. In other words, AdaBoost<T> complete implementation should be linked in the same compilation unit that main (where it is used) is.
This is typically fixed by either #including the .cpp file at the end of your .hpp file (if you want to maintain them separate), or just using only the .hpp file implementing the whole class there.
You have multiple problems.
First, you use the unconventional technique of explicit instantiation in a CPP file. As others have pointed out, convention (but nothing more) requires that you put the implementation in the .H file to allow for generic instantiation. You don't have to do this, but if you did, the readfile() error would go away. (As an alternative, put your AdaBoost<double> instantiation after the definition of AdaBoost::readfile.)
Next, you have declared, but not defined, your constructor and destructor. If you wish to use the compiler-provided constructor and destructor you should delete the declarations. If you wish to use your own constructor and dstructor, you should define them.
Best practice is to get rid of AdaBoost.cpp, and modify AdaBoost.h to include the implementation inline in the header. (Note that this best practice is for templated classes; other advice may apply to non-templated classes.)
You need to put the definition of template<class T>
int AdaBoost<T>::readFromFile(char* fName) into AdaBoost.h, and remove AdaBoost.cpp from your build.
It's best to put all template code into the header. C++ linkers are required to eliminate duplicate instantiations of template code so you won't get "multiply defined symbol" errors.
P.S. You should declare the function as template<class T>
int AdaBoost<T>::readFromFile(const char* fName) to get rid of the deprecated conversion from string constant to ‘char*’ warning. The function does not need to alter the filename.
Related
I am working on a project which uses the LLVM YAML I/O library. This is the documentation/tutorial that I am following:
https://www.llvm.org/docs/YamlIO.html
I am trying to replicate the example where you define a specialization on llvm::yaml::MappingTraits for a struct data type. This example is at the top of the page.
This is my code that I have written:
#include <cstdlib> /* for EXIT_FAILURE */
#include <string>
#include <vector>
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/YAMLParser.h"
using std::string;
using std::vector;
using llvm::outs;
using llvm::errs;
using llvm::yaml::ScalarEnumerationTraits;
using llvm::yaml::MappingTraits;
using llvm::yaml::IO;
using llvm::yaml::Input;
using llvm::yaml::Output;
struct Person {
string name;
int hatSize;
};
template <>
struct MappingTraits<Person> {
static void mapping(IO& io, Person& info) {
io.mapRequired("name", info.name);
io.mapOptional("hat-size", info.hatSize);
}
};
int main(int argc, const char **argv) {
Person tom;
tom.name = "Tom";
tom.hatSize = 8;
Person dan;
dan.name = "Dan";
dan.hatSize = 7;
std::vector<Person> persons;
persons.push_back(tom);
persons.push_back(dan);
Output yout(llvm::outs());
yout << persons;
return EXIT_SUCCESS;
}
It seems to me that I have replicated the example code that they have in that tutorial exactly. But when I try to compile the program (using makefile) I get this cryptic error message:
clang++ -I/usr/local/include -std=c++11 -fno-exceptions -fno-rtti -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -std=c++14 -fcxx-exceptions -g -Wall -c -o yaml_project.o yaml_project.cpp
In file included from yaml_project.cpp:12:
/usr/local/include/llvm/Support/YAMLTraits.h:1871:36: error: implicit instantiation of undefined template 'llvm::yaml::MissingTrait<std::vector<Person, std::allocator<Person> > >'
char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
^
yaml_project.cpp:153:10: note: in instantiation of function template specialization 'llvm::yaml::operator<<<std::vector<Person, std::allocator<Person> > >' requested here
yout << persons;
^
/usr/local/include/llvm/Support/YAMLTraits.h:307:8: note: template is declared here
struct MissingTrait;
^
1 error generated.
<builtin>: recipe for target 'yaml_project.o' failed
make: *** [yaml_project.o] Error 1
I don't think that the error is in the command that I am using to compile this program, because it has worked for me before to compile and link the LLVM libraries into my executable. I think that the problem is in the code, but I cannot identify what.
The code for the mentioned header file llvm/Support/YAMLTraits.h is here:
https://llvm.org/doxygen/YAMLTraits_8h_source.html
Reading the documentation, it seems to me that support for your specific vector<Person> requires registration with a macro:
LLVM_YAML_IS_SEQUENCE_VECTOR(Person)
// or
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Person)
See, Utility Macros: https://llvm.org/docs/YamlIO.html#id22
In the following code, I create a Builder template, and provide a default implementation to return nothing. I then specialize the template with int, to return a value 37.
When I compile with -O0, the code prints 37, which is the expected result. But when I compile using -O3, the code prints 0.
The platform is Ubuntu 20.04, with GCC 9.3.0
Can anyone helps me understand the behavior?
builder.h
class Builder {
public:
template<typename C>
static C build() {
return 0;
}
};
builder.cc
#include "builder.h"
template<>
int Builder::build<int>() {
return 37;
}
main.cc
#include "builder.h"
#include <iostream>
int main() {
std::cout << Builder::build<int>() << '\n';
}
makefile
CXX_FLAG = -O0 -g
all:
g++ $(CXX_FLAG) builder.cc -c -o builder.o
g++ $(CXX_FLAG) main.cc builder.o -o main
clean:
rm *.o
rm main
You should add a forward declaration for build<int>() to builder.h, like so:
template<>
int Builder::build<int>();
Otherwise, while compiling main.cc, the compiler sees only the generic template, and is allowed to inline an instance of the generic build() function. If you add the forward declaration, the compiler knows you provided a specialization elsewhere, and will not inline it.
With -O3, the compiler tries to inline, with -O0 it will not inline anything, hence the difference.
Your code actually violates the "One Definition Rule": it will create two definitions for Builder::build<int>(), but they are not the same. The standard says the result is undefined, but no diagnostics are required. That is a bit unfortunate in this case, as it would have been helpful if a warning or error message was produced.
I have a project which uses the autotools build system to create a static library. I wish to test this library by making a small test program which links to it.
The test program is being created in the code::blocks IDE. The paths containing the headers have been added to the search directories, and the included library added.
When I compile my test program I get the following error:
obj/Debug/main.o: In function `givens':
<snip> undefined reference to `xhypot(double, double)'
However, xhypot is a global function declared, in an included header in real.h as:
nr_double_t xhypot (const nr_double_t, const nr_double_t);
and defined in a companion file real.cpp.
nr_double_t xhypot (const nr_double_t a, const nr_double_t b) {
nr_double_t c = fabs (a);
nr_double_t d = fabs (b);
if (c > d) {
nr_double_t e = d / c;
return c * sqrt (1 + e * e);
}
else if (d == 0)
return 0;
else {
nr_double_t e = c / d;
return d * sqrt (1 + e * e);
}
}
The type nr_double_t is defined in config.h as:
/* The global type of double representation. */
#define nr_double_t double
Where the offending call to xhypot occurs is in a static helper function for a template class like so:
static nr_double_t
givens (nr_double_t a, nr_double_t b, nr_double_t& c, nr_double_t& s) {
nr_double_t z = xhypot (a, b);
c = a / z;
s = b / z;
return z;
}
However, xhypot is also called in other non-static member functions of the class with the exact same syntax (i.e. xhypot(double,double) and if I replace the line nr_double_t z = xhypot (a, b); in this static method with the line nr_double_t z = 0.0; the error disappears.
Here is the entirety of my test program:
#include "config.h"
#include "m_trsolver.h"
int main (int argc, char ** argv)
{
char infile[] = "test.net";
m_trsolver the_m_trsolver;;
return 0;
}
And the full build log:
g++ -Wall -DHAVE_CONFIG_H -g -I../qucs/qucs-core -I../qucs/qucs-core/src -I../qucs/qucs-core/src/components -I../qucs/qucs-core/src/components/devices -I../qucs/qucs-core/src/components/digital -I../qucs/qucs-core/src/components/verilog -I../qucs/qucs-core/src/components/microstrip -I../qucs/qucs-core/src/converter -I../qucs/qucs-core/src/m-interface -I../qucs/qucs-core/src/math -c /home/s0237326/src/qucs_m_interface_test/main.cpp -o obj/Debug/main.o
/home/s0237326/src/qucs_m_interface_test/main.cpp: In function ‘int main(int, char**)’:
/home/s0237326/src/qucs_m_interface_test/main.cpp:10: warning: unused variable ‘infile’
g++ -L../qucs/qucs-core -L../qucs/qucs-core/src -L../qucs/qucs-core/src/components -L../qucs/qucs-core/src/components/devices -L../qucs/qucs-core/src/components/digital -L../qucs/qucs-core/src/components/verilog -L../qucs/qucs-core/src/components/microstrip -L../qucs/qucs-core/src/converter -L../qucs/qucs-core/src/m-interface -L../qucs/qucs-core/src/math -o bin/Debug/qucs_m_interface_test obj/Debug/main.o ../qucs/qucs-core/src/libqucsatorfull.a
obj/Debug/main.o: In function `givens':
/home/s0237326/src/qucs_m_interface_test/../qucs/qucs-core/src/eqnsys.cpp:1341: undefined reference to `xhypot(double, double)'
obj/Debug/main.o: In function `main':
/home/s0237326/src/qucs_m_interface_test/main.cpp:11: undefined reference to `m_trsolver::m_trsolver()'
/home/s0237326/src/qucs_m_interface_test/main.cpp:13: undefined reference to `m_trsolver::~m_trsolver()'
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 0 seconds)
3 errors, 1 warnings
I'm using code::blocks 10.05 on Scientific Linux 6.1 with gcc 4.4.6 and I'm passing -DHAVE_CONFIG_H as there's lots of
#if HAVE_CONFIG_H
# include <config.h>
#endif
In the sources, with config.h being generated by autoconf. I should also add that the code compiles fine when built as a program. I have extracted a subset of the code for this program (all but one file) to put into this static library.
The template class is spread over two files, eqnsys.h and eqnsys.cpp. I know it is not best practice to do this, it has probably been done as it is quite large. It is not my code. eqnsys.cpp is included at the bottom of eqnsys.h ( #include "eqnsys.cpp"). The static helper function is defined in eqnsys.cpp. real.h is #includeed at the top of eqnsys.cpp but not eqnsys.h in case this is relevant. Adding the following to the top of eqnsys.cpp:
template class eqnsys<nr_complex_t>;
template class eqnsys<nr_double_t>;
To force instantiation does not resolve the issue. If I change the givens function to be a member function instead of a static helper function the error disappears. This is the route I might take, but what is the real root of the issue so I can avoid it in future?
Based on the build command line, you're only compiling main.cpp and you're not linking any libraries. You must a link a library which contains the missing symbols, or compile their sources into your executable as well.
In your case, I think the correct solution is to link the static library (which you're trying to test) into your test program.
This is almost certainly a template instantiation issue due to the fact that your template code is in the .cpp not the .h.
Either move your code to the header - so that when the compiler needs it it can instantiate the template for the type required on the fly or leave code in .cpp but force instantiation of the template (at the top of your .cpp file) for the template arg you need by adding . E.g:
// Explicite template instantiations
#pragma warning(disable: 4660) // For template-class specialization is already instantiated.
template class MyTemplateClass<MyTemplateParamClass>;
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 9 years ago.
It's the first time that I try to use templates in my functions but I can't seem to make them work. I defined my function in a file called ddc.hpp
#ifndef __DIGITAL_DOWN_CONVERTER_H__
#define __DIGITAL_DOWN_CONVERTER_H__
namespace ddc {
template <class T> void perform_resampling(std::vector<T> &, unsigned int, unsigned int);
}
#endif
and implemented it in ddc.cpp
#include "ddc.hpp"
template <class T>
void ddc::perform_resampling(std::vector<T> &data, unsigned int f1, unsigned int f2) {
// do stuff
}
and here's my main.cpp
#include "ddc.hpp"
int main() {
std::vector<float> v (100000);
ddc::perform_resampling(v, 1000, 10);
return 0;
}
Compiling with gcc (linux) I get the following error:
$ g++ -c ddc.cpp -o ddc.o -Wall -O3 -lm -m64
$ g++ -c main.cpp -o main.o -Wall -O3 -lm -m64
$ g++ ddc.o main.o -o ../bin/resampler
main.o: In function `main':
main.cpp:(.text.startup+0xed): undefined reference to `void ddc::perform_resampling<float>(std::vector<float, std::allocator<float> >&, unsigned int, unsigned int)'
collect2: ld returned 1 exit status
make: *** [../bin/HW_3] Error 1
Am I doing something wrong?
Template definitions need to go with declarations, so everything needs to be in the header file.
You need to put your template implementation in the header too.
You need to place the definition of the template function in a location that is visible to the code that uses it or use explicit template instantiation to ensure the code for the function is generated.
If you do not want to expose the implemention of perform_resampling you can still force the the compiler to explicitly generate the code for it. The following line when placed in ddc.cpp will instruct the compiler to generate code for perform_resampling taking a vector<float> as it's first parameter.
template void ddc::perform_resampling(std::vector<float> &data, unsigned int f1, unsigned int f2);
I'm not an experienced C++ programmer and I'm having problems compiling. I've got a Heap class that uses a template:
template <class T>
class Heap
{
public:
Heap(const vector<T>& values);
private:
vector<T> d;
// etc.
};
And then in a separate implementation file:
template <class T>
Heap<T>::Heap(const vector<T>& values)
{
d = values;
for (unsigned int i = d.size()-1; i > 0; i--) Heapify(ParentIndex(i));
}
// ... more implementation code ...
And finally a main.cc file:
int main (int argc, char *argv[])
{
vector<int> in;
unsigned int i;
while (cin >> i) in.push_back(i);
Heap<int> h = Heap<int>(in);
return 0;
}
I get these compile errors:
g++ -Wall -I/opt/local/include -c -o main.o main.cc
g++ -Wall -I/opt/local/include -c -o heap.o heap.cc
g++ -Wall -o heap main.o heap.o
Undefined symbols:
"Heap<int>::Heap(std::vector<int, std::allocator<int> > const&)", referenced from:
_main in main.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [heap] Error 1
Why does this not compile? I think the linker is saying it can't find the constructor, but I know it made the object file.
Templates need to be defined 100% within the header file. If you have your Heap<T> implementation in a .cc / .cpp file that is the problem. Move all of the code to the header file and it should fix your issue.
According to the C++ standard, you can use the export keyword thus:
export template<typename foo>...
However, most compilers don't support this. The C++ FAQ has some more info: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.14
See JaredPar's answer for something that's actually reliable.