views:

56

answers:

1

(C++) I've got a number of Entry classes, and got BaseProcessor interface which incapsulates Entry processing logic. (see code below)

The Entry doesn't provide operator<(). The BaseProcessor provides a pointer to less(Entry, Entry) function which is specific for particular BaseProcessor implementation.

I can use the function pointer to compare Entry instances in my program. However I need to create std::set (or std::map, or something else that uses less() ) for Entry class. I've tried to use std::binary_function derived class to pass it to std::set, but it looks like I can't pass a function pointer value to a template.

How can I do this? Is it possible with C++03?

Thanks.

struct Entry
{
  // ...
private: 
  bool operator< (const Entry &) const; // Should be defined by BaseProcessor.
};

typedef bool (*LessFunc)(const Entry &, const Entry &);

class BaseProcessor
{
public:
  // ...
  virtual LessFunc getLessFunc () const = 0;
};

// ...

BaseProcessor *processor = getProcessor();
LessFunc lessfunc = processor->getLessFunc();

Entry e1;
Entry e2;
bool isLess = lessfunc(e1, e2);  // OK

typedef std::set<Entry, ???> EntrySetImpl; // how to use lessfunc here?
EntrySetImpl entries;   
+5  A: 

Have you tried this?

typedef std::set<Entry, LessFunc> EntrySetImpl;
EntrySetImpl entries(lessfunc);

Note that you need to specify the type of your comparison function or object as a template parameter to set, and then give it an instance of the comparison function or object when you actually create a set.


I'll edit my answer to address your follow-up question, because it's a bit easier.

You can define a template like this:

template <LessFunc func> class MyContainer { /*code*/ };

However, the catch is, you must specify a specific function, not a function pointer variable, as the template argument. So, for example, this is OK:

bool CompareEntries1(const Entry &, const Entry &);
MyContainer<CompareEntries1> container;

...but this isn't OK:

bool CompareEntries1(const Entry &, const Entry &);
LessFunc lessfunc = &CompareEntries1; //or any other way of getting a LessFunc
MyContainer<lessfunc> container;

If you have used array template classes, like boost::array, you might have seen something like this before. You can write array<int, 10> to declare a 10-element array, but you can't write array<int, abs(x)>, for example. The size of the array must be something the compiler can be told while it's compiling the program, but before it runs. (There are a very specific set of rules about what's allowed - even if it seems like the compiler should be able to work out what the template argument is, like in the LessFunc example above, it still has to follow the specific rules. In the case of function pointer template arguments, the argument must be the name of a function, or & followed by the name of a function.)

Doug
Yes, it works. Thank you a lot.
Roman
However... It looks like there is no way to use a function pointer value as non-type template parameter. Right? Something like "template <LessFunc func> class Comparator {...} "
Roman
@Roman - you're allowed to do that as well, for classes that you write, but `set` doesn't work like that. However, the `LessFunc` you specify as a template argument must be a compile-time constant (it can't be the result of calling a function, for example).
Doug
I've tried to use my Comparator like this: "Comparator<lessfunc> comparator;" and got the error "‘lessfunc’ cannot appear in a constant-expression"...
Roman
OK, looks like I can apply only the first solution in my case. Thank you a lot again for your explanations.
Roman