PeteK
asked on
function objects with internal state in Visual C++
I want to sort an STL list using a function object with a state. The function object needs a pointer to determine which object (CContourPortionMatch) is greater.
Problem:
The list.sort(..) ignores the (initialised) function object passed to it and creates its own (uninitialised) object using the default constructor.
Questions:
1) Is this a dead end? Is there a way I can get list.sort(..) to work with function objects that have states using Microsoft's STL (I'm hopeful)?
2)Is it worthwhile to switch to a different STL library for windows? Is there a bug-free (or less buggy) one out there that I could drop in?
Code:
CContour *pContour = (*iContour).first;
ASSERT_VALID(pContour);
///////////////
// Sort List //
///////////////
//Create (initialised)function object
std::greater<CContourPorti onMatch> Test2(pContour);
//Sort lowest to highest
//(bug: creates own object here using default constructor of greater<CContourPortionMat ch>)
pList->sort(Test2);
Where greater<CContourPortionMat ch> is defined as:
////////////////////////// //////
// Function object definition //
////////////////////////// //////
// (see http://support.microsoft.com/support/kb/articles/Q265/1/09.ASP
// for bug that requires the function object to be defined
// this way)
template<>
class std::greater<CContourPorti onMatch> : public binary_function<CContourPo rtionMatch ,CContourPortionMatch, bool>
{
public:
//Constructor I want to use
std::greater<CContourPorti onMatch>(C Contour * pContour)
{ m_pContourToUse = pContour;};
// Constructor that is called by sort(and is necessary for compilation)
std::greater<CContourPorti onMatch>() {m_pContourToUse =NULL;};
//This function is called by the sort using an uninitialised object
bool operator()(const CContourPortionMatch & Match1, const CContourPortionMatch &Match2) const
{
//Get start indices for contour in matches
int bStartIndex1 = Match1.GetStartIndex(m_pCo ntourToUse );
int bStartIndex2 = Match2.GetStartIndex(m_pCo ntourToUse );
return (bStartIndex1 < bStartIndex2);
}
//The contour to use for comparison of starting indices
//Must be valid for comparison to work (bug: is never valid)
CContour * m_pContourToUse;
};
Problem:
The list.sort(..) ignores the (initialised) function object passed to it and creates its own (uninitialised) object using the default constructor.
Questions:
1) Is this a dead end? Is there a way I can get list.sort(..) to work with function objects that have states using Microsoft's STL (I'm hopeful)?
2)Is it worthwhile to switch to a different STL library for windows? Is there a bug-free (or less buggy) one out there that I could drop in?
Code:
CContour *pContour = (*iContour).first;
ASSERT_VALID(pContour);
///////////////
// Sort List //
///////////////
//Create (initialised)function object
std::greater<CContourPorti
//Sort lowest to highest
//(bug: creates own object here using default constructor of greater<CContourPortionMat
pList->sort(Test2);
Where greater<CContourPortionMat
//////////////////////////
// Function object definition //
//////////////////////////
// (see http://support.microsoft.com/support/kb/articles/Q265/1/09.ASP
// for bug that requires the function object to be defined
// this way)
template<>
class std::greater<CContourPorti
{
public:
//Constructor I want to use
std::greater<CContourPorti
{ m_pContourToUse = pContour;};
// Constructor that is called by sort(and is necessary for compilation)
std::greater<CContourPorti
//This function is called by the sort using an uninitialised object
bool operator()(const CContourPortionMatch & Match1, const CContourPortionMatch &Match2) const
{
//Get start indices for contour in matches
int bStartIndex1 = Match1.GetStartIndex(m_pCo
int bStartIndex2 = Match2.GetStartIndex(m_pCo
return (bStartIndex1 < bStartIndex2);
}
//The contour to use for comparison of starting indices
//Must be valid for comparison to work (bug: is never valid)
CContour * m_pContourToUse;
};
ASKER
jkr, I tried:
static CContour * m_pContourToUse;
but it produced a linker error:
ContourPortionMatcher.obj : error LNK2001: unresolved external symbol "public: static class CContour * std::greater<class CContourPortionMatch>::m_p ContourToU se" (?m_pContourToUse@?$greate r@VCContou rPortionMa tch@@@std@ @2PAVCCont our@@A)
I think I'm in the market for a C++ compiler that has a good STL. Dinkumware? STLPort?
static CContour * m_pContourToUse;
but it produced a linker error:
ContourPortionMatcher.obj : error LNK2001: unresolved external symbol "public: static class CContour * std::greater<class CContourPortionMatch>::m_p
I think I'm in the market for a C++ compiler that has a good STL. Dinkumware? STLPort?
>>jkr, I tried:
>>static CContour * m_pContourToUse;
You did that within the class declaration? If not, that would explain the error - I was thinking of
template<>
class std::greater<CContourPorti onMatch> : public binary_function<CContourPo rtionMatch ,CContourPortionMatch,
bool>
{
public:
//Constructor I want to use
std::greater<CContourPorti onMatch>(C Contour * pContour)
{ m_pContourToUse = pContour;};
// Constructor that is called by sort(and is necessary for compilation)
std::greater<CContourPorti onMatch>() {m_pContourToUse =NULL;};
//This function is called by the sort using an uninitialised object
bool operator()(const CContourPortionMatch & Match1, const CContourPortionMatch &Match2) const
{
//Get start indices for contour in matches
int bStartIndex1 = Match1.GetStartIndex(m_pCo ntourToUse );
int bStartIndex2 = Match2.GetStartIndex(m_pCo ntourToUse );
return (bStartIndex1 < bStartIndex2);
}
public:
static CContour * m_pContourToUse;
};
>>static CContour * m_pContourToUse;
You did that within the class declaration? If not, that would explain the error - I was thinking of
template<>
class std::greater<CContourPorti
bool>
{
public:
//Constructor I want to use
std::greater<CContourPorti
{ m_pContourToUse = pContour;};
// Constructor that is called by sort(and is necessary for compilation)
std::greater<CContourPorti
//This function is called by the sort using an uninitialised object
bool operator()(const CContourPortionMatch & Match1, const CContourPortionMatch &Match2) const
{
//Get start indices for contour in matches
int bStartIndex1 = Match1.GetStartIndex(m_pCo
int bStartIndex2 = Match2.GetStartIndex(m_pCo
return (bStartIndex1 < bStartIndex2);
}
public:
static CContour * m_pContourToUse;
};
ASKER
I tried it in the class declaration but I got the linking error.
>>but I got the linking error
Hum hum - try a 'Rebuild All' that sometimes helps in these cases...
Hum hum - try a 'Rebuild All' that sometimes helps in these cases...
Did you get the same exact error?
>>I think I'm in the market for a C++ compiler that has a good STL. Dinkumware? STLPort?
The reason why you're getting an error is because you have the implementation for m_pContourToUse static member in your *.cpp code.
You would have this problem regardless of what compiler you would use.
To my knowledge, there are no compilers that will correctly compile template code that has implementation in the *.cpp file.
To remove the error, implement m_pContourToUse in your *.h file, but make sure you put a header gaurd around it.
The reason why you're getting an error is because you have the implementation for m_pContourToUse static member in your *.cpp code.
You would have this problem regardless of what compiler you would use.
To my knowledge, there are no compilers that will correctly compile template code that has implementation in the *.cpp file.
To remove the error, implement m_pContourToUse in your *.h file, but make sure you put a header gaurd around it.
ASKER
I rebuilt everything and got the same error. The error goes away if I remove 'static' from the class declaration. Here is the complete output:
Linking...
CleftFinder.obj : error LNK2001: unresolved external symbol "public: static class CContour * std::greater<class CContourPortionMatch>::m_p ContourToU se" (?m_pContourToUse@?$greate r@VCContou rPortionMa tch@@@std@ @2PAVCCont our@@A)
ContourPortionMatcher.obj : error LNK2001: unresolved external symbol "public: static class CContour * std::greater<class CContourPortionMatch>::m_p ContourToU se" (?m_pContourToUse@?$greate r@VCContou rPortionMa tch@@@std@ @2PAVCCont our@@A)
SliceJoiner.obj : error LNK2001: unresolved external symbol "public: static class CContour * std::greater<class CContourPortionMatch>::m_p ContourToU se" (?m_pContourToUse@?$greate r@VCContou rPortionMa tch@@@std@ @2PAVCCont our@@A)
Debug/CryoTactics.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.
Linking...
CleftFinder.obj : error LNK2001: unresolved external symbol "public: static class CContour * std::greater<class CContourPortionMatch>::m_p
ContourPortionMatcher.obj : error LNK2001: unresolved external symbol "public: static class CContour * std::greater<class CContourPortionMatch>::m_p
SliceJoiner.obj : error LNK2001: unresolved external symbol "public: static class CContour * std::greater<class CContourPortionMatch>::m_p
Debug/CryoTactics.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.
>>The error goes away if I remove 'static' from the class
declaration.
That's because static members have to be implemented outside of the class declaration. If you want m_pContourToUse to be static, you need to add implementation for it.
declaration.
That's because static members have to be implemented outside of the class declaration. If you want m_pContourToUse to be static, you need to add implementation for it.
ASKER
Axter, I have the declaration of class std::greater<CContourPorti onMatch> (with m_pContourToUse) in the header file of CContourPortionMatch (ContourPortionMatch.h).
The call to pList->sort(Test2) code is in the .cpp file of another class (CSliceJoiner in SliceJoiner.cpp).
The call to pList->sort(Test2) code is in the .cpp file of another class (CSliceJoiner in SliceJoiner.cpp).
I'm not sure if you understand what I'm trying to say, so I'll give you an example, but it's a non template class example:
//My header file foo.h
class foo
{
static int m_MyStaticMemeber;
int m_MyNonStaticMemeber;//Don 't need anything else for non-static members
};
//My source file foo.cpp
int foo::MyStaticMemeber; //Need this for static members
//My header file foo.h
class foo
{
static int m_MyStaticMemeber;
int m_MyNonStaticMemeber;//Don
};
//My source file foo.cpp
int foo::MyStaticMemeber; //Need this for static members
OK, just to test the functionality (and to address the 'static' problem later), try and make it a global variable...
FYI,
I had a type-O. That should have been:
int foo::m_MyStaticMemeber; //Need this for static members
I had a type-O. That should have been:
int foo::m_MyStaticMemeber; //Need this for static members
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Testing now...
ASKER
Thanks jkr and Axter. I appreciate it.
I added the static member implementation and it worked (and in the process discovered a bug in my code that may have interfered with the original problem).
Axter, I'll post a "points for Axter" transfer for you.
Thanks again. Its good to have help from people who can see both the forest and the trees.
I added the static member implementation and it worked (and in the process discovered a bug in my code that may have interfered with the original problem).
Axter, I'll post a "points for Axter" transfer for you.
Thanks again. Its good to have help from people who can see both the forest and the trees.
Welcome, and thanks for the points.
Thanx :o)
BTW: After thinking about that for a while, I really cannot imagine another way to achieve that...
BTW: After thinking about that for a while, I really cannot imagine another way to achieve that...
You could make 'm_pContourToUse' static for the functor class and use it like
//Create (initialised)function object
std::greater<CContourPorti
std::greater<CContourPorti
//Sort lowest to highest
pList->sort(Test2);