拆分模板化C++;类转换为.hpp/.cpp文件--可能吗? 我试图编译一个C++模板类,它在一个 .HPP和.CPP< /Cord>文件:之间出错。 $ g++ -c -o main.o main.cpp $ g++ -c -o stack.o stack.cpp $ g++ -o main main.o stack.o main.o: In function `main': main.cpp:(.text+0xe): undefined reference to 'stack<int>::stack()' main.cpp:(.text+0x1c): undefined reference to 'stack<int>::~stack()' collect2: ld returned 1 exit status make: *** [program] Error 1 $g++-c-o main.o main.cpp $g++-c-o stack.o stack.cpp $g++-o main.o stack.o main.o:在函数“main”中: main.cpp:(.text+0xe):对“stack::stack()”的未定义引用 main.cpp:(.text+0x1c):对“stack::~stack()”的未定义引用 collect2:ld返回了1个退出状态 make:**[程序]错误1

拆分模板化C++;类转换为.hpp/.cpp文件--可能吗? 我试图编译一个C++模板类,它在一个 .HPP和.CPP< /Cord>文件:之间出错。 $ g++ -c -o main.o main.cpp $ g++ -c -o stack.o stack.cpp $ g++ -o main main.o stack.o main.o: In function `main': main.cpp:(.text+0xe): undefined reference to 'stack<int>::stack()' main.cpp:(.text+0x1c): undefined reference to 'stack<int>::~stack()' collect2: ld returned 1 exit status make: *** [program] Error 1 $g++-c-o main.o main.cpp $g++-c-o stack.o stack.cpp $g++-o main.o stack.o main.o:在函数“main”中: main.cpp:(.text+0xe):对“stack::stack()”的未定义引用 main.cpp:(.text+0x1c):对“stack::~stack()”的未定义引用 collect2:ld返回了1个退出状态 make:**[程序]错误1,c++,class,templates,header,linker,C++,Class,Templates,Header,Linker,这是我的密码: 堆栈.hpp: #ifndef _STACK_HPP #define _STACK_HPP template <typename Type> class stack { public: stack(); ~stack(); }; #endif #include <iostream> #include "stack.hpp" template <typename Type> stack

这是我的密码:

堆栈.hpp

#ifndef _STACK_HPP
#define _STACK_HPP

template <typename Type>
class stack {
    public:
            stack();
            ~stack();
};
#endif
#include <iostream>
#include "stack.hpp"

template <typename Type> stack<Type>::stack() {
        std::cerr << "Hello, stack " << this << "!" << std::endl;
}

template <typename Type> stack<Type>::~stack() {
        std::cerr << "Goodbye, stack " << this << "." << std::endl;
}
#include "stack.hpp"

int main() {
    stack<int> s;

    return 0;
}
\ifndef\u STACK\u水电站
#定义\u堆栈\u水电站
模板
类堆栈{
公众:
堆栈();
~stack();
};
#恩迪夫
堆栈.cpp

#ifndef _STACK_HPP
#define _STACK_HPP

template <typename Type>
class stack {
    public:
            stack();
            ~stack();
};
#endif
#include <iostream>
#include "stack.hpp"

template <typename Type> stack<Type>::stack() {
        std::cerr << "Hello, stack " << this << "!" << std::endl;
}

template <typename Type> stack<Type>::~stack() {
        std::cerr << "Goodbye, stack " << this << "." << std::endl;
}
#include "stack.hpp"

int main() {
    stack<int> s;

    return 0;
}
#包括
#包括“stack.hpp”
模板堆栈::堆栈(){

std::cerr不,这是不可能的。如果没有
export
关键字,它实际上并不存在


最好将函数实现放在“.tcc”或“.tpp”中文件,并且#在.hpp文件末尾包含.tcc文件。然而,这仅仅是表面的;它仍然与在头文件中实现所有内容相同。这只是使用模板所付出的代价。

因为模板是在需要时编译的,这就对多文件项目强制了一个限制:实现(定义)模板类或函数的定义必须与其声明位于同一文件中。这意味着我们不能在单独的头文件中分离接口,并且我们必须在使用模板的任何文件中同时包含接口和实现。

您需要在hpp文件中包含所有内容。问题是这些类实际上不是直到编译器发现其他cpp文件需要它们时才创建,因此它必须拥有所有代码,以便在那时编译模板类


我倾向于做的一件事是尝试将我的模板拆分为通用的非模板部分(可以在cpp/hpp之间拆分)和继承非模板类的特定于类型的模板部分。

仅当您
包括“stack.cpp
位于
stack.hpp
的末尾。我只建议在实现相对较大的情况下使用此方法,并且如果您将.cpp文件重命名为另一个扩展名,以便将其与常规代码区分开来。

另一种可能性是执行以下操作:

#ifndef _STACK_HPP
#define _STACK_HPP

template <typename Type>
class stack {
    public:
            stack();
            ~stack();
};

#include "stack.cpp"  // Note the include.  The inclusion
                      // of stack.h in stack.cpp must be 
                      // removed to avoid a circular include.

#endif
\ifndef\u STACK\u水电站
#定义\u堆栈\u水电站
模板
类堆栈{
公众:
堆栈();
~stack();
};
#include“stack.cpp”//注意include
//stack.cpp中stack.h的
//删除以避免循环包含。
#恩迪夫

我不喜欢这个建议,只是样式问题,但是它可能适合你。< /P> < P>“导出”关键字是将模板实现与模板声明分开的方法。这是在没有现有实现的C++标准中引入的。在适当的时候只有几个编译器才实现它。p> 有时,如果您可以将所有模板参数的公共功能提取到非模板类中(可能是类型不安全),则可能会将大部分实现隐藏在cpp文件中。然后,标头将包含对该类的重定向调用。在与“模板膨胀”作斗争时,也会使用类似的方法问题。

问题在于模板不会生成实际的类,它只是一个告诉编译器如何生成类的模板。您需要生成一个具体的类

简单自然的方法是将方法放在头文件中,但还有另一种方法

在.cpp文件中,如果您对所需的每个模板实例化和方法都有引用,编译器将在那里生成它们,以便在整个项目中使用

新堆栈。cpp:

#include <iostream>
#include "stack.hpp"
template <typename Type> stack<Type>::stack() {
        std::cerr << "Hello, stack " << this << "!" << std::endl;
}
template <typename Type> stack<Type>::~stack() {
        std::cerr << "Goodbye, stack " << this << "." << std::endl;
}
static void DummyFunc() {
    static stack<int> stack_int;  // generates the constructor and destructor code
    // ... any other method invocations need to go here to produce the method code
}
#包括
#包括“stack.hpp”
模板堆栈::堆栈(){

如果您知道堆栈将用于什么类型,那么可以在cpp文件中明确地实例化它们,并将所有相关代码保存在那里

也可以跨DLL(!)导出这些内容,但要获得正确的语法(特定于MS的_declspec(dllexport)和export关键字的组合)非常困难

我们在一个以double/float为模板的math/geom库中使用了它,但是有很多代码。(当时我在谷歌上搜索过,但现在没有这些代码。)

只要您知道需要什么样的实例化,这是可能的

在stack.cpp的末尾添加以下代码,它就可以工作了:

template class stack<int>;
模板类栈;

堆栈的所有非模板方法都将实例化,链接步骤将正常工作。

不可能在单独的cpp文件中编写模板类的实现并进行编译。如果有人声称,所有这样做的方法都是模拟单独cpp文件用法的变通方法,但实际上如果您打算编写模板class库并将其与头文件和lib文件一起分发以隐藏实现,这是完全不可能的

要知道原因,让我们看看编译过程。头文件从不编译。它们只是预处理。然后预处理的代码与实际编译的cpp文件结合在一起。现在,如果编译器必须为对象生成适当的内存布局,它需要知道模板类的数据类型


实际上,必须理解的是,template类根本不是一个类,而是一个类的模板,该类的声明和定义是由编译器在编译时从参数中获取数据类型信息后生成的。只要无法创建内存布局,方法定义的指令就可以记住类方法的第一个参数是'this'运算符。所有cl
#include <iostream>
#include "Stack.hpp"
using namespace std;

template<class T>
void Stack<T>::Push(T val) {
    cout << "Pushing Value " << endl;
    this->val = val;
}

template<class T>
T Stack<T>::Pop() {
    cout << "Popping Value " << endl;
    return this->val;
}

template <class T> Stack<T>::Stack() {
    cout << "Construct Stack " << this << endl;
}

template <class T> Stack<T>::~Stack() {
    cout << "Destruct Stack " << this << endl;
}
#include <iostream>
using namespace std;

#include "Stack.hpp"

int main() {
    Stack<int> s;
    s.Push(10);
    cout << s.Pop() << endl;
    return 0;
}
> Construct Stack 000000AAC012F8B4
> Pushing Value
> Popping Value
> 10
> Destruct Stack 000000AAC012F8B4