Reputation: 1738
----------------
// fishers.h
#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <math.h>
#include <cstring>
namespace tsfresh
{
template<typename T=double>
class FisherTest {
static_assert(std::is_floating_point_v<T>, "FisherTest template T must be float or double");
public:
FisherTest();
T pvalue(int a, int b, int c, int d);
private:
T pValueLog(int a, int b, int c, int d);
};
}
// fishers.cpp
#include "fishers.h"
namespace tsfresh
{
template<typename T>
FisherTest<T>::FisherTest() {
}
template<typename T>
T FisherTest<T>::pvalue(int a, int b, int c, int d) {
return pValueLog(a,b,c,d);
}
template<typename T>
T FisherTest<T>::pValueLog(int a, int b, int c, int d) {
return 0;
}
}
//---
// https://www.codeproject.com/Articles/48575/How-to-Define-a-Template-Class-in-a-h-File-and-Imp
void TempFunc()
{
tsfresh::FisherTest<float> FisherTestFloatObj;
tsfresh::FisherTest<double> FisherTestDoubleObj;
}
// main.cpp
#include <cassert>
#include <iostream>
#include <vector>
#include "fishers.h"
using namespace std;
bool floatEqual(double a, double b) {
return fabs(a-b) <= 1e-6;
}
int main()
{
auto fisher = tsfresh::FisherTest<double>();
int a[] = {1,2,3,4};
cout << fisher.pvalue(a[0], a[1], a[2], a[3]) << "\n";
cout << "All tests passed\n";
return 0;
}
I need to hide implementation details in cpp file, so I need to separate header and source file of my template class. I make 2 instances of the template class that I want to use in the .cpp file (following the solution in the link above), but I still get linking error.
The compile command I use is: g++ -o test main.cpp fishers.cpp -std=c++17
I get the following error: main.cpp:(.text+0x93): undefined reference to
tsfresh::FisherTest::pvalue(int, int, int, int)'`
What do I need to change to make this work? I always used header-only template classes, so I don't know what went wrong.
Upvotes: 0
Views: 164
Reputation: 1
What do I need to change to make this work?
You need to put the implementation of class template FisherTest
's member functions inside the header file fishers.h
as shown below:
fishers.h
#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <math.h>
#include <cstring>
namespace tsfresh
{
template<typename T=double>
class FisherTest {
static_assert(std::is_floating_point_v<T>, "FisherTest template T must be float or double");
public:
FisherTest();
T pvalue(int a, int b, int c, int d);
private:
T pValueLog(int a, int b, int c, int d);
};
//implementation
template<typename T>
FisherTest<T>::FisherTest() {
}
template<typename T>
T FisherTest<T>::pvalue(int a, int b, int c, int d) {
return pValueLog(a,b,c,d);
}
template<typename T>
T FisherTest<T>::pValueLog(int a, int b, int c, int d) {
return 0;
}
}
//declaration for tempfunc
void TempFunc();
fishers.cpp
#include "fishers.h"
void TempFunc()
{
tsfresh::FisherTest<float> FisherTestFloatObj;
tsfresh::FisherTest<double> FisherTestDoubleObj;
}
main.cpp
#include <cassert>
#include <iostream>
#include <vector>
#include "fishers.h"
#include <type_traits>
using namespace std;
bool floatEqual(double a, double b) {
return fabs(a-b) <= 1e-6;
}
int main()
{
auto fisher = tsfresh::FisherTest<double>();
int a[] = {1,2,3,4};
cout << fisher.pvalue(a[0], a[1], a[2], a[3]) << "\n";
cout << "All tests passed\n";
return 0;
}
Demo.
Some of the modifications that i made include:
FisherTest
to the header fishers.h
.TempFunc
inside header file fishers.h
.TempFunc
is indside the source file fishers.cpp
.Upvotes: 1