如何使用最小包含创建一个用模板函数包装对象的库?

时间:2010-10-25 22:18:29

标签: c++ templates

该项目的目标是创建一个分发库。在过去,我使用了前向声明,所以我不必分发一堆头文件和库。但是,我现在正试图通过切换到模板来消除代码重复,并遇到了一些问题。

首先,一个简单的示例项目显示当前正在运行的内容:

//LibraryDep1.h

class LibraryDep1
{
public:
    LibraryDep1(void) {};
    virtual ~LibraryDep1(void) {};

    template <typename T>
    int TestFunction(T value)
    {
        std::cout << value << std::endl;
        return 0;
    }
};


//LibraryInclude.h

class LibraryDep1; //forward declare

class LibraryInclude
{
private:
    LibraryDep1* mLibDep1;
public:
    LibraryInclude(void);
    virtual ~LibraryInclude(void);

    int TestFunction(int value);
    int TestFunction(std::string value);


};

//LibraryInclude.cpp

#include "LibraryInclude.h"
#include "LibraryDep1.h"


LibraryInclude::LibraryInclude(void)
{
    this->mLibDep1 = new LibraryDep1();
}


LibraryInclude::~LibraryInclude(void)
{
    delete this->mLibDep1;
}

int LibraryInclude::TestFunction(int value)
{
    return this->mLibDep1->TestFunction(value);
}

int LibraryInclude::TestFunction(std::string value)
{
    return this->mLibDep1->TestFunction(value);
}

//main.cpp
#include <tchar.h>
#include "LibraryInclude.h"

int _tmain(int argc, _TCHAR* argv[])
{
    LibraryInclude inclLibrary;
    inclLibrary.TestFunction(77);
    inclLibrary.TestFunction("test");
}

这给出了预期的输出:

77
test

但是,LibraryInclude::TestFunction的重载可以用模板函数替换,以进一步减少代码重复:

//LibraryInclude.h

class LibraryDep1; //forward declare

class LibraryInclude
{
private:
    LibraryDep1* mLibDep1;
public:
    LibraryInclude(void);
    virtual ~LibraryInclude(void);

    template <typename T>
    int TestFunction(T value) {
      return mLibDep1->TestFunction(value);
    }

};

现在的问题是我使用的是mLibDep1而没有包含完整的实现,这给我一个未定义的类型编译错误。这意味着我需要在LibraryInclude.h中#include "LibraryDep1.h",因此要求我将LibraryInclude.h和LibraryDep1.h分发给我的库。这是一个简单的例子,如果我要切换到使用模板化版本的LibraryInclude,真正的项目有许多头文件需要分发。

我的问题是,有没有办法避免不得不用我的库分发一堆包含文件并消除代码重复?或者,我最好只是在分布式头文件中重载所有已知类型(大大降低库灵活性)并仅将模板保留在底层类中?

2 个答案:

答案 0 :(得分:1)

没有。目前没有办法做你想要的。当编译器供应商开始实施'export'关键字时,你会很幸运。目前我只知道Comeau这样做。这个关键词已存在多年,所以在其他关键词实现之前我不会屏住呼吸。

答案 1 :(得分:1)

一个非常有限和丑陋的解决方案是:

//LibraryDep1.h

#pragma once
#include <iostream>

class LibraryDep1
{
public:
    LibraryDep1(void) {};
    virtual ~LibraryDep1(void) {};

    template <typename T>
    int TestFunction(T value)
    {
        std::cout << value << std::endl;
        return 0;
    }
};

//LibraryInclude.h

#pragma once

class LibraryDep1; //forward declare

class LibraryInclude
{
private:
   LibraryDep1* mLibDep1;

public:
    LibraryInclude(void);
    virtual ~LibraryInclude(void);

    template <typename T>
    int TestFunction(T value);
};

//LibraryInclude.cpp

#include "LibraryInclude.h"
#include "LibraryDep1.h"

#include <string>

LibraryInclude::LibraryInclude(void)
{
    mLibDep1 = new LibraryDep1();
}

LibraryInclude::~LibraryInclude(void)
{
}

// only to save some typing when only forwaring calls
#define LI_TESTFUNCTION( TYPE ) \
template<> \
int LibraryInclude::TestFunction<TYPE>( TYPE value ) {\
   return mLibDep1->TestFunction(value); \
}

// the allowed specializations, everything else causes link errors
LI_TESTFUNCTION( int );
LI_TESTFUNCTION( std::string );

使用VC ++ 2k8&amp; g ++ 4.3.4静态链接LibraryInclude.o