0

I'm looking at boost::lambda as a way to to make a generic algorithm that can work with any "getter" method of any class.

The algorithm is used to detect duplicate values of a property, and I would like for it to work for any property of any class.

In C#, I would do something like this:

class Dummy
{
    public String GetId() ...
    public String GetName() ...
}

IEnumerable<String> FindNonUniqueValues<ClassT>
  (Func<ClassT,String> propertyGetter) { ... }

Example use of the method:

var duplicateIds   = FindNonUniqueValues<Dummy>(d => d.GetId());
var duplicateNames = FindNonUniqueValues<Dummy>(d => d.GetName());

I can get the for "any class" part to work, using either interfaces or template methods, but have not found yet how to make the "for any method" part work.

Is there a way to do something similar to the "d => d.GetId()" lambda in C++ (either with or without Boost)?

Alternative, more C++ian solutions to make the algorithm generic are welcome too.

I'm using C++/CLI with VS2008, so I can't use C++0x lambdas.

ckarras
  • 4,946
  • 2
  • 33
  • 37
  • 1
    If it fits for you, a *"more c++ian solution"* would be to go with the style of the `` functions, see e.g. `unique()`/`unique_copy()`. – Georg Fritzsche May 01 '10 at 20:16
  • My understanding is that an algorithm similar to unique() would work if I had a vector and wanted to find non-unique T in the vector, but not in the case where I'm looking for non-unique T.method() – ckarras May 01 '10 at 20:31
  • Many algorithm calls like `unique()` have a second form that allows to pass a predicate, which is used instead of the default operation - e.g. `unique(myVec.begin(), myVec.end(), myComparator())`. – Georg Fritzsche May 01 '10 at 23:40

2 Answers2

6

Assuming, I understand what you're looking for, you can use boost::bind:

FindNonUniqueValues<Dummy>(boost::bind(&Dummy::GetId, _1));

Actually, you just need boost::mem_fn or even std::mem_fun, but boost::bind will allow you a bit more generality.

In this case, you would define FindNonUniqueValues as something like:

template <typename T>
/* ? */ FindNonUniqueValues(boost::function<std::string (const T&)> getter) { ... }

Here, I'm not really sure how your FindNonUniqueValues gets its list of objects (or exactly what it's supposed to return - is an IEnumerable like an iterator?), so you could fill that in.

Jesse Beder
  • 33,081
  • 21
  • 109
  • 146
  • Thanks, I tried both boost::bind and std::mem_fun. Both solutions work, but I found that std::mem_fun better fits with what I was looking for. – ckarras May 01 '10 at 20:29
2

For future reference, here's the solution I ended with, after following ideas from the accepted answer:

template < typename ObjectT, typename ValueT > std::vector <ObjectT>
FindInstancesWithDuplicateValue(
   vector<ObjectT> allValues, mem_fun_ref_t<ValueT, ObjectT> getter)
{ 
    // [...create a *sorted* list of  ObjectT, ordered by ObjectT.getter()...]
    // [...loop through the sorted list to find identical adjacent values...]
        // call the mem_fun_ref_t:
        ValueT value1 = getter(*iterPrev);
        ValueT value2 = getter(*iter);
        if (value1 == value2) // duplicates found
    // ...
}

Example use:

vector<Dummy> list;
list.push_back(Dummy(1, "1-UniqueValue"));
list.push_back(Dummy(2, "2-DuplicateValue"));
list.push_back(Dummy(3, "2-DuplicateValue"));
list.push_back(Dummy(4, "3-UniqueValue"));

vector<Dummy> dummyWithduplicateNames = 
    FindInstancesWithDuplicateValue<Dummy,CString>
    (list, mem_fun_ref(&Dummy::GetName));

// returns Dummy(2, "2-DuplicateValue") and Dummy(3, "2-DuplicateValue")
ckarras
  • 4,946
  • 2
  • 33
  • 37