将模板类编译/链接为静态库

时间:2012-11-20 16:10:35

标签: gcc reference g++ static-libraries

我正在研究一个程序并测试模板类(我需要它)我写了一个小的(和bug,可能是2或3个逻辑错误,我的目标是让它编译)堆栈类。我想要做的是将其编译为静态库(.a),然后将其与主程序链接。

错误是:

main.cpp:(.text+0x1c): undefined reference to `Stack<int>::Stack()'
main.cpp:(.text+0x31): undefined reference to `Stack<int>::push(int)'
main.cpp:(.text+0x42): undefined reference to `Stack<int>::push(int)'
main.cpp:(.text+0x4e): undefined reference to `Stack<int>::pop()'
main.cpp:(.text+0x5d): undefined reference to `Stack<int>::pop()'
collect2: error: ld returned 1 exit status

这是头文件:

/* stack.h */
#ifndef _STACK_INCLUDED_
#define _STACK_INCLUDED_
template<typename T>
struct Node
{
    T* node;
    Node<T>* next;
};

template<typename T>
class Stack
{
private:
    Node<T>* bottom;
public:
    Stack();
    Stack(T first);
    Stack(T* arr, int amount);
    void push(T push);
    T* pop();
};
/* I added the following prototypes in an attempt to correct the error,
did not work*/
template<typename T>
Stack<T>::Stack();

template<typename T>
Stack<T>::Stack(T first);

template<typename T>
Stack<T>::Stack(T* arr, int amount);

template<typename T>
void Stack<T>::push(T push);

template<typename T>
T* Stack<T>::pop();

#endif

以下是实施文件:

/* stack.cpp */
#include "../heads/stack.h"
#define null (void*)0

template<typename T>
Stack<T>::Stack() {
    bottom = null;
}
template<typename T>
Stack<T>::Stack(T first) {
    push(first);
}
template<typename T>
Stack<T>::Stack(T* arr, int amount)
{
    int i;
    for(i=0;i<amount; i++)
    {
        push(arr[i]);
    }
}
template<typename T>
void Stack<T>::push(T push)
{
    Node<T>* tmp = new Node<T>();
    tmp->node = push;
    tmp->next = null;

    Node<T>* node = bottom;
    while(node->next != null)
    {
        node = node->next;
    }
    node->next = tmp;
}
template<typename T>
T* Stack<T>::pop()
{
    int i=0;
    Node<T>* node = bottom;
    while(node->next != null)
    {
        i++;
        node = node->next;
    }
    node = bottom;
    for(;i>1;i++)
    {
        node = node->next;
    }
    Node<T>* res = node->next;
    node->next = null;
    return res->node;
}

您可能已经注意到包含头文件:“../ heads /stack.h”,这是因为结构如下所示:

- root
-- CLASSNAME
--- implementation of CLASSNAME
-- heads
--- all the headers
-- obj
--- object files (compiled)
--bin
---final output

makefile看起来像这样:

CC=g++
CFLAGS=-c -fpermissive -Wall
LFLAGS=-llua
OBJ=obj
BIN=bin
HS=heads

all: $(OBJ)/bind.a $(OBJ)/stack.a $(OBJ)/main.o
    $(CC) $(LFLAGS) -o $(BIN)/main $(OBJ)/main.o $(OBJ)/bind.a $(OBJ)/stack.a
$(OBJ)/bind.o: binds/bind.cpp $(HS)/bind.h
    $(CC) $(CFLAGS) binds/bind.cpp -o $(OBJ)/bind.o
$(OBJ)/bind.a: $(OBJ)/bind.o
    ar -cvq $(OBJ)/bind.a $(OBJ)/bind.o
$(OBJ)/main.o:
    $(CC) $(CFLAGS) main/main.cpp -o $(OBJ)/main.o
$(OBJ)/stack.o: $(HS)/stack.h stack/stack.cpp
    $(CC) $(CFLAGS) stack/stack.cpp -o $(OBJ)/stack.o
$(OBJ)/stack.a: $(OBJ)/stack.o
    ar -cvq $(OBJ)/stack.a $(OBJ)/stack.o
clean:
    touch $(OBJ)/dummy
    rm $(OBJ)/*

编译器:g ++ 4.7.2(gcc-multilib)
操作系统:Arch Linux(x86_64)(内核3.6.6-1)

你可以得到整个文件here(我正在进行多次测试,所以不要介意-llua标志和其他文件,你可以根据需要更改Makefile,我只是想弄明白这个)。

经过一些研究和测试,我注意到这些符号没有被导出,(nm obj/stack.o没有显示任何内容,而nm obj/bind.o则显示。(.a))。 但是我找不到任何关于在这种情况下做什么的参考。

1 个答案:

答案 0 :(得分:0)

您不能为每个可能的模板参数创建一个lib,但您可以为某些类型创建。

模板化类用于生成采用给定类型的类的代码。

当有一个实例使用它时,它会生成实际的类,否则,在编译时它将被简单地省略。

根据Compile header-only template library into a shared library?,这可以通过使用 Explicit Instantiation 来实现,并将您声明的类型设置为lib,并让其余类型在编译中生成。