遵循教程时出现 C++ 模板类标头-源分离链接错误

C++ template class header-source separation linking error when following tutorial

提问人:Huy Le 提问时间:3/8/2022 最后编辑:Huy Le 更新时间:3/8/2022 访问量:127

问:

----------------
// 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;
}

我需要在cpp文件中隐藏实现细节,因此我需要将模板类的头文件和源文件分开。我制作了 2 个要在 .cpp 文件中使用的模板类实例(按照上面链接中的解决方案),但我仍然收到链接错误。

我使用的编译命令是:g++ -o test main.cpp fishers.cpp -std=c++17

我收到以下错误:tsfresh::FisherTest::p value(int, int, int, int)''main.cpp:(.text+0x93): undefined reference to

我需要更改什么才能使这项工作正常工作?我总是使用仅标头模板类,所以我不知道出了什么问题。

C++ 模板 编译器错误 链接器 错误

评论

0赞 user12002570 3/8/2022
您需要将类模板成员函数的实现放在标头中。

答:

1赞 user12002570 3/8/2022 #1

我需要更改什么才能使这项工作正常工作?

你需要把类模板的成员函数的实现放在头文件中,如下图所示:FisherTestfishers.h

渔民.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();

渔民.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;
}

演示

我所做的一些修改包括:

  1. 将类模板的成员函数的实现移到了 header 中。FisherTestfishers.h
  2. 添加了内部头文件的声明。TempFuncfishers.h
  3. 对应的定义是源文件旁边。TempFuncfishers.cpp

评论

0赞 Huy Le 3/8/2022
我需要实现隐藏在 .cpp 文件中
0赞 user12002570 3/8/2022
@HuyLe 为什么你没有在原来的问题中提到这个重要的细节?有关您的后续问题(即如何隐藏实现),请参阅是否可以隐藏模板类的实现?或提出单独的问题。
0赞 Huy Le 3/8/2022
那么这个链接中的解决方案是错误的吗?codeproject.com/Articles/48575/......
1赞 user12002570 3/8/2022
@HuyLe 他们的第一个解决方案似乎不起作用,演示。此外,在他们的第二个解决方案中,他们包含了一个源文件,这绝不是推荐的解决方案。TestTemp.cpp