akappa
akappa

Reputation: 10490

C++: specifying a base class for a template parameter

I need to design a framework that computes the result of a divide-et-conquer algorithm in parallel. In order to use the framework, the user needs to specify somehow the procedure that implements the "divide" phase (a function from T to T), the "conquer" phase (a function from D to D) and T and D themselves.

I've thought it would be nice to define two abstract classes, BaseDivide and BaseConquer, which declares a pure virtual method compute with the right types: that way I have a type which implements a well-defined concept (from the point of view of the framework) with the user-definable function included by means of derivation of the abstract classes.

I've thought to use templates to pass the types to the framework, so the user doesn't have to instantiate them in order to use the framework, so something like that:

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

My problem is that I want that Divide and Conquer to be derived types of BaseDivide and BaseConquer: there is a way to enforce it at compile time? Also: do you think I can achieve a similar result with a cleaner design?

Upvotes: 7

Views: 5648

Answers (3)

Joel Falcou
Joel Falcou

Reputation: 6357

Use Boost.EnabelIf to trigger SFINAE when your types don't fulfill your requirement. Checking if T is derived from U is doen with boost::is_base_of :

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

Upvotes: 2

Gunther Piez
Gunther Piez

Reputation: 30419

You could create the base classes like this:

struct BaseDivide {
    enum EnumDiv { derivedFromBaseDivide = true };
}

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

What is the purpose of the additional Divide and Conquer template parameters? Are you sure you need them?

Upvotes: 4

Scott Moonen
Scott Moonen

Reputation: 748

You don't need to use templates for this purpose. Instead, you can use pointers to BaseDivide and BaseConquer objects, and polymorphism will do the job for you.

Upvotes: 1

Related Questions