C++ 如何在VisualStudio中导出从显式实例化模板派生的类?

C++ 如何在VisualStudio中导出从显式实例化模板派生的类?,c++,visual-studio,templates,inheritance,explicit-instantiation,C++,Visual Studio,Templates,Inheritance,Explicit Instantiation,在我的DLL中,我有一个类模板和从该模板的实例化派生的第二个类。这两类产品均应出口,并可用于其他DLL。编译器是Visual Studio 2013。我希望模板代码只在一个翻译单元中实例化,所以我采用显式实例化 DLL1中的代码分布如下。 基类模板: // In BaseTemplate.h: #pragma once template<typename T> class BaseTemplate { public: T foo(T t); }; // declare

在我的DLL中,我有一个类模板和从该模板的实例化派生的第二个类。这两类产品均应出口,并可用于其他DLL。编译器是Visual Studio 2013。我希望模板代码只在一个翻译单元中实例化,所以我采用显式实例化

DLL1中的代码分布如下。 基类模板:

// In BaseTemplate.h:
#pragma once

template<typename T> 
class BaseTemplate
{
public:
    T foo(T t);
};

// declare explicit instantiation
extern template class BaseTemplate < int >;    

// In BaseTemplate.cpp:
#include "BaseTemplate.h"

// template method definition
template<class T>
T BaseTemplate<T>::foo(T t)
{
    return t;
}

// explicit instantiation and export
template class __declspec(dllexport) BaseTemplate < int >;    
//在BaseTemplate.h中:
#布拉格语一次
模板
类基模板
{
公众:
T foo(T T),;
};
//声明显式实例化
外部模板类BaseTemplate;
//在BaseTemplate.cpp中:
#包括“BaseTemplate.h”
//模板方法定义
模板
T BaseTemplate::foo(T)
{
返回t;
}
//显式实例化和导出
模板类uu declspec(dllexport)BaseTemplate
派生类:

// In Derived.h:
#pragma once
#include "BaseTemplate.h"

#ifdef DLL1_EXPORTS // this is predefined in DLL1
#define DLL1_API __declspec(dllexport)
#else
#define DLL1_API __declspec(dllimport)
#endif

class DLL1_API Derived : public BaseTemplate < int >
{
public:
    void bar();
};
//在派生的.h中:
#布拉格语一次
#包括“BaseTemplate.h”
#ifdef DLL1\u EXPORTS//这是在DLL1中预定义的
#定义DLL1_API__declspec(dllexport)
#否则
#定义DLL1_API___declspec(dllimport)
#恩迪夫
类DLL1_API派生:公共基模板
{
公众:
空心钢筋();
};
理论上,extern语句阻止在除BaseTemplate.cpp之外的所有翻译单元中进行实例化,BaseTemplate.cpp执行显式实例化。但是,我得到以下警告(在我的项目中被视为错误,因此会破坏构建):

1>basetemplate.h(19):警告C4661:'int basetemplate::foo(T)'
1> 没有为显式模板实例化请求提供合适的定义
1> 与
1> [
1> T=int
1> ]
1> h(15):参见“basetemplate::foo”的声明
派生类的导出似乎会触发实例化,而忽略extern语句。如果我从派生类中删除导出宏,DLL1将在没有警告的情况下编译(但其他DLL显然将无法链接)。如果我在派生类而不是继承类中聚合BaseTemplate类型的成员,它也可以工作(即使在导出时)


如何在Visual Studio中组合显式模板实例化和导出的派生类?

从Microsoft开发者支持中,我得到了以下问题的答案:

这是当前的设计:在这种情况下,将“u declspec(dllexport)”应用于类“派生”意味着将导出“派生”的所有方法及其基类,为了导出作为类模板成员的方法,编译器需要实例化类模板及其所有方法。如果在其他地方提供了方法的定义(在本例中就是这样),则编译器无法导出该方法,因此会发出警告。注意:导出类模板的方法不仅仅是实例化它——生成的符号具有不同的“链接”和(稍微)不同的损坏名称

通过这一陈述和我自己的实验,我得出了以下结论。每当存在导出的派生类(或类模板)时,基类模板的实现必须对派生类可见。此外,我发现
extern
语句本身并不能取代
dllimport
,这在我的问题中的示例代码中是缺失的

可以将显式实例化和仅头部实现结合起来。但是,在VisualStudio中,在派生时无法避免额外的实例化。以下是我目前采用的模式:

在BaseTemplate.h中:

#pragma once

template<typename T> 
class BaseTemplate
{
public:
    T foo(T t);
};

// Declare explicit instantiation.
#ifdef DLL1_EXPORTS // this is predefined in DLL1
    // Avoid duplicate instantation within DLL1, except for inheritance.
    extern template class BaseTemplate < int >;    
#else
    // Provide instantiation for other DLLs.
    template class __declspec(dllimport) BaseTemplate < int >;
#endif

// Include implementation in header to enable inheritance 
// (and possibly further instantiations in other DLLs).
#include "BaseTemplate_impl.h"
#pragma一次
模板
类基模板
{
公众:
T foo(T T),;
};
//声明显式实例化。
#ifdef DLL1\u EXPORTS//这是在DLL1中预定义的
//避免DLL1中的重复实例化,继承除外。
外部模板类BaseTemplate;
#否则
//为其他DLL提供实例化。
模板类uu declspec(dllimport)BaseTemplate;
#恩迪夫
//在标头中包含实现以启用继承
//(并可能在其他DLL中进一步实例化)。
#包括“BaseTemplate_impl.h”
在BaseTemplate_impl.h中:

// template method definition
template<class T>
T BaseTemplate<T>::foo(T t)
{
    return t;
}
//模板方法定义
模板
T BaseTemplate::foo(T)
{
返回t;
}
在BaseTemplate.cpp中:

#include "BaseTemplate.h"     

// explicit instantiation and export
template class __declspec(dllexport) BaseTemplate < int >;
#包括“BaseTemplate.h”
//显式实例化和导出
模板类uu declspec(dllexport)BaseTemplate
在第h节中:

#pragma once
#include "BaseTemplate.h"

#ifdef DLL1_EXPORTS // this is predefined in DLL1
#define DLL1_API __declspec(dllexport)
#else
#define DLL1_API __declspec(dllimport)
#endif

class DLL1_API Derived : public BaseTemplate < int >
{
public:
    void bar();
};
#pragma一次
#包括“BaseTemplate.h”
#ifdef DLL1\u EXPORTS//这是在DLL1中预定义的
#定义DLL1_API__declspec(dllexport)
#否则
#定义DLL1_API___declspec(dllimport)
#恩迪夫
类DLL1_API派生:公共基模板
{
公众:
空心钢筋();
};
#pragma once
#include "BaseTemplate.h"

#ifdef DLL1_EXPORTS // this is predefined in DLL1
#define DLL1_API __declspec(dllexport)
#else
#define DLL1_API __declspec(dllimport)
#endif

class DLL1_API Derived : public BaseTemplate < int >
{
public:
    void bar();
};