7

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?

akappa
  • 10,220
  • 3
  • 39
  • 56
  • 1
    This has bugged me many times. This is the sort of issue that C++0x "concepts" help to handle. – DataGraham May 04 '11 at 18:30
  • I think I just don't like "duck typing": among other things, it is bad because the code doesn't tell you in an explicit way what kind of types the library expects (you have to discover it "the hard way" or just relying on the documentation). In Java you can write something like class T, which I use a lot in my applications. – akappa May 04 '11 at 18:42

3 Answers3

4

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?

Gunther Piez
  • 29,760
  • 6
  • 71
  • 103
  • Nice: a bit kludgy, but nice! BTW, T and D are the argument and return types of Divide::compute and Conquer::compute, I think I need them in the template, otherwise how I can declare the variables holding the intermediate results? – akappa May 04 '11 at 18:38
  • If you have intermediate values the additional parameters are ok, they will make it probably simpler – Gunther Piez May 04 '11 at 19:45
2

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);
Joel Falcou
  • 6,247
  • 1
  • 17
  • 34
1

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.

Scott Moonen
  • 738
  • 4
  • 8
  • but, as I said, the user should give to the library two of these instances, and I don't want that because instantiating them would expose to the user concepts which I'd like to keep "internal". – akappa May 04 '11 at 18:25
  • Ok, sorry, I missed that point. Well, at a minimum, if your framework treats the classes as though they were based on these base classes, you should get compile errors. I'm not sure at the moment if there's a cleaner way to do it, however. – Scott Moonen May 04 '11 at 18:30
  • In fact, you may not even need to define these base classes. If in your framework you simply assume that the provided classes have a "compute" function, then you will get compile errors if they do not. This doesn't feel elegant from a specification perspective, but seems like it would behave as you want. – Scott Moonen May 04 '11 at 18:34
  • Yes, you're right, but "duck typing" has never got me :) I think it is because I come from Java, and in Java you can specify a base class for your generic types. – akappa May 04 '11 at 18:39