Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using a template function as dll in another project

Tags:

c++

dll

I have a simple function like this:

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)
{
    .
    .
    .
    .
    .
}

and I created a dll using these two lines:

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

and I called this function in other Project using this method:

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);

this works very fine, but now I changed my function to this

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

but Visual Studio won't allow extern "C" __declspec (dllexport) with template functions is there any way to do this easily?actually I'm not expert,so would you please explain this to me in detail?

like image 552
Alexander1991 Avatar asked Feb 25 '14 08:02

Alexander1991


2 Answers

There is no such thing as a "template function." There is a function template, however; that is a template from which functions are created by instantiation. In this case, the distinction is important.

To call a function instantiated from a template, you must have access to that instantiation. The most common case is to implement the template in a header file and simply #include it (see this SO question for more details). I believe that you want your function to be usable with arbitrary client-supplied types as LinearOperation and Vector, so a header-only implementation is your only option.


If, on the other hand, you know all the types you would want to instantiate the template with when building your library, you can actually explicitly instantiate the template for those types and export these explicit instantiations. Like this:

Header file

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

Source file

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.

Such instantiations cannot be extern "C", however (they all have the same function name, after all). So if you want to load them dynamically, you'll have to provide uniquely-named C-linkage accessors to them.

Still, I believe what you're really looking for is implementing the funciton in a header file.


Based on your comments, here is how you could actually make your library dynamically loadable while using CUSP internally.

You cannot have a function template in your library's public interface. So let's say you want to allow using your library with the following types of LinearOperator: OperatorCharm and OperatorTop, and with the following types of Vector: FancyVector<float> and FancyVector<double>. Then, your public interface could look like this:

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

You don't even have to instantiate the template explicitly any more, since it will be instantiated implicitly for the calls in the EXPORT-ed functions.

So in effect, your public API will be those 4 cuspDsolver_a_b functions, which can be queried dynamically as normal.

like image 196
Angew is no longer proud of SO Avatar answered Oct 26 '22 01:10

Angew is no longer proud of SO


Template functions are not compiled and thus not part of a DLL as there's an infinite number of function derived from a template.

Only specific instances of the template are compiled and linked into a binary. You can expose those specialized template functions in a DLL. You'll need a header file for those names as string them in a hardcoded string is problematic.

If you want to use a template function w/o specializing it, export it through a header file.

like image 36
egur Avatar answered Oct 26 '22 01:10

egur