Answered by:
Using "->Find" on a "List" in Visual C++

Question
-
I'm trying to teach myself Visual C++ and I've written the following class in Visual C++:
public ref class EntityStruc{ public: String^ Entity; String^ System; String^ Type; public: ~EntityStruc(){ } EntityStruc(String^ EntityIn, String^ SystemIn, String^ TypeIn){ this->Entity = EntityIn; this->System = SystemIn; this->Type = TypeIn; } };
And then used that definition in a routine that looks something like this:
void Fill(List<EntityStruc^>^ EntityTable){ EntityStruc^ SoughtEntity; EntityStruc^ ReturnEntity; EntityTable->Clear(); EntityTable->Add(gcnew EntityStruc("Ball", "", "")); EntityTable->Add(gcnew EntityStruc("Bat", "", "")); EntityTable->Add(gcnew EntityStruc("Boy", "", "")); SoughtEntity->Entity = "Boy"; ReturnEntity = EntityTable->Find(SoughtEntity); } }
Which throws the following compile error:
error C2664: 'System::Collections::Generic::List<T>::Find' : cannot convert parameter 1 from 'EntityStruc ^' to 'System::Predicate<T> ^'
I've also tried:
ReturnEntity = EntityTable->Find(delegate(SoughtEntity){};)
Which returns:
error C3861: 'delegate': identifier not found
As well as a plagerised C# version of:
ReturnEntity = EntityTable->Find(delegate(SoughtEntity){ return SoughtEntity->Entity == "Boy"; };)
After acknowledging that I really don't know what I'm doing here I thought it best to ask for some assistance.
1. Does the Visual C++ language support the Find method on the List object?
2. If so, how would I do the above and a little explanation so I understand what's happening would be greatly appreciated.Sunday, November 14, 2010 10:23 AM
Answers
-
The Find method is supported but as the C# version shows it takes a delegate of type Predicate and not an instance of the object you're searching for.
What C++/CLI does not support is "annonymous delegates" which is what the C# version of the code is using. To do this in C++/CLI you need a separate function:
bool IsBoy(SoughtEntity ^entity) { return entity->Entity == "Boy"; }
and then Find can be used like this:
ReturnEntity = EntityTable->Find(gcnew Predicate<SoughtEntity>(IsBoy));
- Marked as answer by shiftingspanner Sunday, November 14, 2010 11:46 AM
Sunday, November 14, 2010 10:54 AM
All replies
-
The Find method is supported but as the C# version shows it takes a delegate of type Predicate and not an instance of the object you're searching for.
What C++/CLI does not support is "annonymous delegates" which is what the C# version of the code is using. To do this in C++/CLI you need a separate function:
bool IsBoy(SoughtEntity ^entity) { return entity->Entity == "Boy"; }
and then Find can be used like this:
ReturnEntity = EntityTable->Find(gcnew Predicate<SoughtEntity>(IsBoy));
- Marked as answer by shiftingspanner Sunday, November 14, 2010 11:46 AM
Sunday, November 14, 2010 10:54 AM -
Thank you for that. Much appreciated. Another silly question leading off from that. Obviously hard coding the search term is a bit limiting. Can I do something like:
bool FindSearchTerm(SoughtEntity ^entity, String ^SearchTerm) { return entity->Entity == SearchTerm; }
And then call it something like:
ReturnEntity = EntityTable->Find(gcnew Predicate<SoughtEntity>(FindSearchTerm("Boy")));
Or would I have to declare the SeachTerm as a global variable, populate it and then call the comparison function?
Sunday, November 14, 2010 11:16 AM -
That doesn't work and using a global variable is better avoided. One option is this:
value class EntityPredicate { String ^what; public: EntityPredicate(String ^term) { what = term; } bool IsMatch(SoughtEntity ^entity) { return entity->Entity == what; } }
Used like this:
void foo() { EntityPredicate p("Boy"); ReturnEntity = EntityTable->Find(gcnew Predicate<SoughtEntity>(p, &EntityPredicate::IsMatch)); }
Sunday, November 14, 2010 12:03 PM -
Mike, thank you very for this. It's going to take me at least two days to work through and make sure I understand what is happening with all of this but you've given a good steer in the right direction.
Sunday, November 14, 2010 12:22 PM -
Just so if anyone else is trying this this is what the final code looked like:
public ref class EntityStruc{ public: String^ Entity; String^ System; String^ Type; public: ~EntityStruc(){ } EntityStruc(String^ EntityIn, String^ SystemIn, String^ TypeIn){ this->Entity = EntityIn; this->System = SystemIn; this->Type = TypeIn; } };
private ref class EntityPredicate{ String^ SearchTerm; public: EntityPredicate(String^ SearchTermIn){ SearchTerm = SearchTermIn; } bool Matched(EntityStruc^ CompareEntity){ return CompareEntity->Entity == SearchTerm; } };
EntityPredicate^ FindEntity; EntityStruc^ ReturnEntity; . . . . //If source isn't in EntityTable then add it FindEntity = gcnew EntityPredicate(Source); ReturnEntity = EntityTable->Find(gcnew Predicate<EntityStruc^>(FindEntity, &EntityPredicate::Matched)); if(ReturnEntity == nullptr){ EntityTable->Add(gcnew EntityStruc(Source, System, "")); }
Thanks again Mike. All due to you.Sunday, November 14, 2010 1:03 PM -
C# has strong support for these cool tricks. Await 'functions' are just wrapper classes for the
.NET Wait() ...as/of keywords in C# are wrapper classes...
See below for a C++/CLI implementation of Predicate<T^>and an effective emulation of the C# anonymous delegate. After seeing this, you will not want to spend almost any time using the .NET Predicate<T>in C++/CLI.
Still, fun to see..cpp file
Star^ CppClasLibrary::TestPredicateByGenericList(Star^ searchStar) { List<Star^>^ myList = gcnew List<Star^>(); for (int i = 0; i < 6; i++) { myList->Add(gcnew Star(L"My Star Name #" + i.ToString(), i+1, i*63)); if(i == 4) myList->Add(gcnew Star(L"The Sun", 69, 433691.4107l)); } m_starList = myList; // Instantiate a 'PredicateDelegate'. PredicateDelegate^ pd = gcnew PredicateDelegate(searchStar); Star^ match = myList->Find(gcnew Predicate<Star^>(pd, &PredicateDelegate::MyFunction)); if (match == nullptr) return gcnew Star(L"<<< Not Found >>>", pd->MyStar->ID); return match; } bool PredicateDelegate::MyFunction(Star^ s) { return (this->MyStar->ID == s->ID); }
.h file
public ref class Star { private: String^ m_starname; int m_code; long long unsigned m_distance; public: const long long _1AU = 149597870700; // 149,597,870,700 meters (~93 million miles) public: Star() {} Star(String^ starname, int code) : m_starname(starname), m_code(code) {} Star(String^ starname, int code, long long distance) : m_starname(starname), m_code(code), m_distance(distance) {} ~Star() {} public: property long long Distance { long long get() { return m_distance; } void set(long long value) { m_distance = value; } } property String^ StarName { String^ get() { return m_starname; } void set(String^ value) { m_starname = value; } } property int ID { int get() { return m_code; } void set(int value) { m_code = value; } } }; public ref class PredicateDelegate { private: Star^ m_star; public: PredicateDelegate() {} PredicateDelegate(Star^ s) : m_star(s) { } ~PredicateDelegate() {} bool MyFunction(Star^ s); property Star^ MyStar { Star^ get() { return m_star; } } }; public ref class CppClasLibrary { private: protected: //delegate bool PredicateDelegate(Star^); public: CppClasLibrary(); CppClasLibrary(List<Object^>^ o); ~CppClasLibrary(); List<Star^>^ m_starList; Star^ TestPredicateByGenericList(Star^ Daniel); bool MyFunction(Star^ id); };
It would be fantastic to see WPF fully supported for C++ and C++/CX in future.
}
Tuesday, September 8, 2015 12:28 PM