C++:为模板参数指定基类

7
我需要设计一个框架,以并行方式计算分治算法的结果。为了使用该框架,用户需要以某种方式指定实现“分”阶段(从T到T的函数)、“治”阶段(从D到D的函数)以及T和D本身的过程。
我认为定义两个抽象类BaseDivide和BaseConquer会很好,它们声明了一个带有正确类型的纯虚方法compute:这样我就有了一个实现了明确定义概念(从框架的角度来看)的类型,并通过抽象类的派生包含了用户可定义的函数。
我考虑使用模板将类型传递给框架,这样用户就不必实例化它们才能使用框架,因此可以做出以下操作:
template <typename T, typename D, typename Divide, typename Conquer> 
D compute(T arg);

我的问题是我希望“分治算法”成为BaseDivideBaseConquer的派生类型:有没有一种方法可以在编译时强制执行它?另外,您认为我能用更清晰的设计达到类似的结果吗?


1
这让我烦恼了很多次。这是C++0x中的“概念”有助于处理的问题类型。 - DataGraham
我认为我不喜欢“鸭子类型”:除了其他问题外,它之所以糟糕是因为代码没有以明确的方式告诉您库期望的类型(您必须“费劲地”发现它或仅依赖于文档)。在Java中,您可以编写类似于class T <V extends E>的内容,我在我的应用程序中经常使用它。 - akappa
3个回答

4
您可以像这样创建基础类:
struct BaseDivide {
    enum EnumDiv { derivedFromBaseDivide = true };
}

template <typename T, typename D, typename Divide, typename Conquer> 
    static_assert(D::derivedFromBaseDivide);
    D compute(T arg);

额外的分治模板参数有什么作用?您确定需要它们吗?


不错:有点笨拙,但还不错!顺便说一下,T和D是Divide :: compute和Conquer :: compute的参数和返回类型,我认为我需要它们在模板中,否则我怎么能声明保存中间结果的变量? - akappa
如果您有中间值,额外的参数是可以的,它们可能会使其更简单。 - Gunther Piez

2
使用Boost.EnableIf来在类型不符合要求时触发SFINAE机制。 使用boost::is_base_of来检查T是否派生自U:
#include <boost/type_traits/is_base_of.hpp>
#include <boost/enable_if.hpp>

template <typename T, typename D, typename Divide, typename Conquer> 
typename boost::
enable_if_c< boost::is_base_of<BaseDivide,Divide>::value 
          && boost::is_base_of<BaseConquer,Conquer>::value
          ,D
          >::type
compute(T arg);

1

您不需要为此目的使用模板。相反,您可以使用指向BaseDivide和BaseConquer对象的指针,多态性将为您完成工作。


但是,正如我所说的,用户应该向库提供这两个实例中的两个,而我不希望这样做,因为实例化它们会向用户暴露我想要保持“内部”的概念。 - akappa
好的,抱歉,我错过了那个点。嗯,至少,如果您的框架将类视为基于这些基类,则应该会出现编译错误。不过,我目前不确定是否有更清晰的方法来做到这一点。 - Scott Moonen
实际上,您甚至可能不需要定义这些基类。如果在您的框架中,您只是假设提供的类具有“compute”函数,那么如果它们没有,则会出现编译错误。从规范的角度来看,这并不优雅,但似乎会按照您的期望行事。 - Scott Moonen
是的,你说得对,但“鸭子类型”从来没有让我感到困扰 :) 我想这是因为我来自Java,而在Java中,你可以为你的泛型类型指定一个基类。 - akappa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接