模板类中的C ++非专用成员

时间:2012-09-02 13:04:58

标签: c++ templates specialization dllexport partial-specialization

我对模板类有疑问。 例如,参加这个课程

template<class TBase> class CTemplateInherit : public TBase
{
public:

    virtual void DoNonSpecializedWork();
    virtual void DoTemplateWork();
    virtual ~CTemplateInherit();
};

// In header file
template<class TBase>
bool CTemplateInherit<TBase>::DoTemplateWork()
{
    std::wcout << L"CTemplateInherit::DoTemplateWork" << std::endl;
    TBase::DoWork();
    return true;
}

// In CPP file
bool CTemplateInherit::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

现在,我希望能够使用dllexport在CPP文件中定义非专用方法,并且只保留标题中的特化。 通常情况下,我认为我可以将成员方法定义为模板化,但因为我从TBase继承是不可能的。

那么我怎么能分开呢?我只覆盖了TBase中的4个方法,并且希望能够将其他40个左右的方法保留为DLL中的DLLEXPORT,而专门化则位于头文件中。

提前感谢您的建议!

3 个答案:

答案 0 :(得分:3)

如果您不想更改课程的hierarchy

1)specialize.cpp文件中所有需要类型的函数。

template<>
bool CTemplateInherit<First>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

template<>
bool CTemplateInherit<Second>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

template<>
bool CTemplateInherit<Nth>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

2)使用

template<typename T>
bool CTemplateInherit<T>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}
.cpp文件中的

,但在header

中使用了类似的内容
template class CTemplateInherit<First>;
template class CTemplateInherit<Second>;
template class CTemplateInherit<Nth>;

3) Dietmar 建议。

答案 1 :(得分:3)

我不太确定你要完成什么,但是在使用模板时,你需要确保在必要时实例化这些模板。当您将模板定义放在标头中时,您可以从编译器获得隐式实例化:每当它看到使用了一个函数模板并且该模板的定义可见时,它将实例化该模板。当您将模板放在其他位置时,编译器在需要时不会看到模板定义,因此不会隐式实例化它。但是,您可以自己实例化相应的功能模板,例如:

// In CPP file
template <class TBase>
bool CTemplateInherit<TBase>::DoNonSpecializedWork()
{
    std::wcout << L"CTemplateInherit::DoNonSpecializedWork" << std::endl;
    return true;
}

template bool CTemplateInherit<SomeBase>::DoNotSpecializeWork();
template bool CTemplateInherit<SomeOtherBase>::DoNotSpecializeWork();

答案 2 :(得分:1)

我认为缺少一条重要信息:非专业方法是否会覆盖TBase类的虚拟方法?这是这里的核心问题。

如果没有,那么您可以为非专业方法创建另一个类,并从CTemplateInherit类中的两个类继承(公开)。问题解决了。

但是,如果非专业方法覆盖了TBase类的虚方法,那么它只会稍微复杂一些:

解决方案1)获取所有非专用函数,并将它们重新组合成一个“细节”标题。作为一组(非模板)自由函数(如果它很容易将输入 - 输出作为参数传递)或作为(非模板)类与它所需的非专用数据成员。然后,在相应的cpp文件(稍后将编译到DLL中)中定义所有这些函数(实现它们)。

然后,在您的CTemplateInherit类模板中,只需将非专用函数调用转发给“detail”函数集。由于模板默认为内联,因此开销为零。如果需要将“detail”函数重新组合成一个类(非模板),那么,只需使用private继承,防止函数名冲突。然后,您可以像任何其他继承的数据成员一样访问“detail”类的数据成员,并且可以将非专用函数调用转发到可以编译为DLL的“detail”类实现(如果您有从DLL导出类的合适框架(因为普通的C ++没有可靠的机制),但你的问题似乎意味着你这样做。

此解决方案的唯一问题是烦人地创建了几个简单的转发功能。但恕我直言,这是一个合理的价格来支付隐藏DLL中的实现(几乎任何时候你想这样做,你最终写了一堆包装函数)。

解决方案2)如果基类中有一组非专用虚函数,那么该子集肯定不依赖于TBase的实际类型(我的意思是,这些函数的原型可以是没有它而形成)。然后,这意味着您可以将该功能子集重新组合到另一个基类中,TBase应该从该基类继承。我们称之为TNonSpecialBase。此时,您可以设置以下层次结构:

class TNonSpecialBase {
  // set of pure-virtual functions that are not special.
};

// this is an example of a class that could act as a TBase:
class TExampleBase : public virtual TNonSpecialBase {
  // set of virtual functions that are special to TExampleBase.
};

class CNonSpecialDerived : public virtual TNonSpecialBase {
  // declaration of non-specialized functions that override the function in TNonSpecialBase.
};

template <typename TBase>
class CTemplateInherit : public TBase, public CNonSpecialDerived {
  // set of virtual functions that are specialized for the template argument TBase.
};

通过上面的设置,专用函数必须最终在CTemplateInherit的头文件中,但在CNonSpecialDerived重新分组的非专用函数可以在单独的cpp文件中定义(并编译)进入DLL)。这里的神奇技巧是使用虚拟继承来允许最终类具有基类TNonSpecialBase的单个虚拟表。换句话说,这允许类CNonSpecialDerived覆盖TBase中继承自TNonSpecialBase的虚函数,只要TBase不覆盖任何这些函数(在这种情况下,编译器将调用它含糊不清)。这样,用户可以处理指向TBase对象的指针,调用其任何虚函数,这将导致向CTemplateInherit实现(专用)或CNonSpecialDerived实现的调度(据推测,在DLL中)。