在另一个项目中使用模板函数作为dll

时间:2014-02-25 08:18:55

标签: c++ dll

我有一个像这样的简单函数:

cusp.dll

#define EXPORT extern "C" __declspec (dllexport)
EXPORT 
void cuspDsolver(int *r, int *c, double *v, double *x, double *b, int size, int nnz,double tol)
{
    .
    .
    .
    .
    .
}

我用这两行创建了一个dll:

#define EXPORT extern "C" __declspec (dllexport)
EXPORT 

我使用这种方法在其他Project中调用了这个函数:

HINSTANCE hDLL = LoadLibrary("C:\\Users\\Administrator\\Documents\\Visual Studio           2012\\Projects\\Ardalan_12\\cusp.dll");
if(hDLL == NULL)
{
    cout<< "Failed to load DLL" <<endl;
}

typedef void(*fnPtr)(int *, int *, double *, double *, double *, int , int ,double);

fnPtr pfn;

pfn=(fnPtr)GetProcAddress(hDLL,"cuspDsolver");

if(pfn)
{
    pfn(rowOffset,colIndex,values,answer,rightHandSide,theSize,nnz,0.9);
}

FreeLibrary(hDLL);

这非常好,但现在我将我的功能改为

//#define EXPORT extern "C" __declspec (dllexport)
//EXPORT 
template <typename LinearOperator,typename Vector>
void cuspDsolver(LinearOperator& A,Vector& X,Vector& B,double tol)
{

    cusp::default_monitor<double> monitor(B, 10000, tol);
    cusp::precond::scaled_bridson_ainv<double,cusp::device_memory> PRE(A);
    DWORD dw1 = GetTickCount();
    cusp::krylov::cg(A,X,B,monitor,PRE);
    DWORD dw2 = GetTickCount();
    double dw3 = dw2 - dw1;
    cout <<endl << "time spent is : " << dw3 << endl;
    cout << endl << "developed by cusp!!!"  << endl;
}

但Visual Studio不允许 extern“C”__ declspec(dllexport) 模板函数有没有办法轻松做到这一点?实际上我不是专家那么请你详细解释一下这个?

2 个答案:

答案 0 :(得分:6)

没有“模板功能”这样的东西。但是有一个功能模板,;这是一个模板,通过实例化从中创建函数。在这种情况下,区别很重要。

要调用从模板实例化的函数,您必须有权访问该实例。最常见的情况是在头文件中实现模板,只需#include它(有关详细信息,请参阅此SO question)。我相信您希望您的函数可以使用任意客户端提供的类型LinearOperationVector,因此只有标题的实现是您唯一的选择。


另一方面,如果您知道在构建库时想要实例化模板的所有类型,您实际上可以显式实例化这些类型的模板并导出这些显式实例化。像这样:

标头文件

template <typename LinearOperator,typename Vector>
void cuspDsolver(LinearOperator& A,Vector& X,Vector& B,double tol);

源文件

template <typename LinearOperator,typename Vector>
void cuspDsolver(LinearOperator& A,Vector& X,Vector& B,double tol)
{
  // body here
}

template __declspec(dllexport) void cuspDsolver(MyConcreteOperator1& A, MyConcreteVector1& X, MyConcreteVector1& B, double tol);
template __declspec(dllexport) void cuspDsolver(MyConcreteOperator2& A, MyConcreteVector2& X, MyConcreteVector2& B, double tol);
// etc.

然而,这样的实例化不能是extern "C"(毕竟它们都具有相同的函数名)。因此,如果要动态加载它们,则必须为它们提供唯一命名的C链接访问器。

不过,我相信你真正想要的是在头文件中实现功能。


根据您的评论,以下是在内部使用CUSP时实际可以动态加载库的方法。

您的图书馆的公共界面中不能有功能模板。因此,假设您希望允许您的库使用以下类型的LinearOperatorOperatorCharmOperatorTop,并使用以下类型的VectorFancyVector<float>FancyVector<double>。然后,您的公共界面可能如下所示:

template <typename LinearOperator,typename Vector>
void cuspDsolver(LinearOperator& A,Vector& X,Vector& B,double tol)
{
  // body
}


EXPORT void cuspDsolver_Charm_float(params_which, correspond_to, OperatorCharm_and, FancyVector_of_float)
{
  cuspDsolver(params);
}

EXPORT void cuspDsolver_Charm_double(params_which, correspond_to, OperatorCharm_and, FancyVector_of_double)
{
  cuspDsolver(params);
}

EXPORT void cuspDsolver_Top_float(params_which, correspond_to, OperatorTop_and, FancyVector_of_float)
{
  cuspDsolver(params);
}

EXPORT void cuspDsolver_Charm_double(params_which, correspond_to, OperatorTop_and, FancyVector_of_double)
{
  cuspDsolver(params);
}

您甚至不必再显式实例化模板,因为它将隐式实例化EXPORT - ed函数中的调用。

因此,实际上,您的公共API将是那些4 cuspDsolver_a_b个函数,可以像往常一样动态查询。

答案 1 :(得分:1)

模板函数未编译,因此不属于DLL的一部分,因为从模板派生的函数数量无限。

仅编译模板的特定实例并将其链接到二进制文件中。您可以在DLL中公开这些专用模板函数。你需要这些名称的头文件作为字符串,它们在硬编码字符串中是有问题的。

如果您想使用模板功能而不对其进行专门化,请通过头文件将其导出。