From: Russ on
Hi all. I must be doing something wrong but cannot figure it out. I
have a data class and a list class, in an extension DLL, declared like
this:

>#define DllExport __declspec (dllexport)

>class DllExport CRate : public CObject {
>public:
> DECLARE_SERIAL (CRate)
> CRate () { m_Rate = 0; }
> CRate (const CRate &in) { *this = in; }
>
> const CRate& operator= (const CRate& in)
> { m_Rate = in.m_Rate; m_Date = in.m_Date; return *this; }
>
> bool operator== (const CRate& in);
> bool operator!= (const CRate& in) { return ! (*this == in); }
>
> virtual void Serialize (CArchive& Ar);
>
> double m_Rate;
> CString m_Date;
>};


>class DllExport CRateList : public CList <CRate, CRate&> {
>public:
> DECLARE_SERIAL (CRateList)
>
> double GetRate () const { return GetHead ().m_Rate; }
> double GetRate (const CString &da) const;
> void SetRate (const double& d, const CString &da);
>
> const CRateList& operator= (const CRateList& in);
>
> bool operator== (const CRateList& in);
> bool operator!= (const CRateList& in)
> { return ! (*this == in); }
>};

The implementation for serialization looks like this:

>IMPLEMENT_SERIAL (CRate, CObject, 1)
>IMPLEMENT_SERIAL (CRateList, CList, 1)


If I leave DllExport out of the class declarations, everything
compiles ok. It is still ok with DllExport only in the CRate class.
But when I put DllExport in the CRateList class, I get a compile error
like this:

"error C2678: binary '==' : no operator found which takes a left-hand
operand of type 'const CRate' (or there is no acceptable conversion)"

This error is attributed to the last line of a helper function called
CompareElements that looks like this (from afxtempl.h):

>template<class TYPE, class ARG_TYPE>
>BOOL AFXAPI CompareElements(const TYPE* pElement1, const ARG_TYPE* pElement2)
>{
> ENSURE(pElement1 != NULL && pElement2 != NULL);
> ASSERT(AfxIsValidAddress(pElement1, sizeof(TYPE), FALSE));
> ASSERT(AfxIsValidAddress(pElement2, sizeof(ARG_TYPE), FALSE));
>
> return *pElement1 == *pElement2;
>}


As far as I can find, that helper is only called from CList::Find
function, which I am not using... And anyway I cannot figure out why
this only happens when I use dllexport.

Help??

Thanks, Russ
From: Joseph M. Newcomer on
See below...
On Thu, 12 Nov 2009 17:46:46 -0500, Russ <russk2t(a)comcast.net> wrote:

>Hi all. I must be doing something wrong but cannot figure it out. I
>have a data class and a list class, in an extension DLL, declared like
>this:
>
>>#define DllExport __declspec (dllexport)
>
>>class DllExport CRate : public CObject {
>>public:
>> DECLARE_SERIAL (CRate)
>> CRate () { m_Rate = 0; }
>> CRate (const CRate &in) { *this = in; }
>>
>> const CRate& operator= (const CRate& in)
>> { m_Rate = in.m_Rate; m_Date = in.m_Date; return *this; }
>>
>> bool operator== (const CRate& in);
****
bool operator==(const CRate & in) const;
****
>> bool operator!= (const CRate& in) { return ! (*this == in); }
****
bool operator != (const CRate & in) const {return !(*this == in); }
****
>>
>> virtual void Serialize (CArchive& Ar);
>>
>> double m_Rate;
>> CString m_Date;
>>};
>
>
>>class DllExport CRateList : public CList <CRate, CRate&> {
>>public:
>> DECLARE_SERIAL (CRateList)
>>
>> double GetRate () const { return GetHead ().m_Rate; }
>> double GetRate (const CString &da) const;
>> void SetRate (const double& d, const CString &da);
>>
>> const CRateList& operator= (const CRateList& in);
>>
>> bool operator== (const CRateList& in);
>> bool operator!= (const CRateList& in)
>> { return ! (*this == in); }
>>};
>
>The implementation for serialization looks like this:
>
>>IMPLEMENT_SERIAL (CRate, CObject, 1)
>>IMPLEMENT_SERIAL (CRateList, CList, 1)
>
>
>If I leave DllExport out of the class declarations, everything
>compiles ok. It is still ok with DllExport only in the CRate class.
>But when I put DllExport in the CRateList class, I get a compile error
>like this:
>
> "error C2678: binary '==' : no operator found which takes a left-hand
>operand of type 'const CRate' (or there is no acceptable conversion)"
>
>This error is attributed to the last line of a helper function called
>CompareElements that looks like this (from afxtempl.h):
>
>>template<class TYPE, class ARG_TYPE>
>>BOOL AFXAPI CompareElements(const TYPE* pElement1, const ARG_TYPE* pElement2)
>>{
>> ENSURE(pElement1 != NULL && pElement2 != NULL);
>> ASSERT(AfxIsValidAddress(pElement1, sizeof(TYPE), FALSE));
>> ASSERT(AfxIsValidAddress(pElement2, sizeof(ARG_TYPE), FALSE));
>>
>> return *pElement1 == *pElement2;
>>}
>
>
>As far as I can find, that helper is only called from CList::Find
>function, which I am not using... And anyway I cannot figure out why
>this only happens when I use dllexport.
>
>Help??
>
>Thanks, Russ
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Goran on
On Nov 12, 11:46 pm, Russ <russ...(a)comcast.net> wrote:
> As far as I can find, that helper is only called from CList::Find
> function, which I am not using...  And anyway I cannot figure out why
> this only happens when I use dllexport.

You need bool op==(...) __const__; // __ emphasis mine.

This is, I guess, because you are exporting a class that derives from
the template class. Since compiler does not know class will be used by
client code (it can't, that code is in another module), compiler
forces the generation of all members for given base class. Some of
these members use CompareElements. But your op== is not correct (and,
you see, CompareElements takes const TYPE* and then calls op==).

I wouldn't export like that. In CRateList, I would expose an interface
I think should be exposed (even if it is a bastardized CList part). I
would either contain CList in CRateList or perhaps derive privately.
What I am saying, BTW, stems from the general rule of thumb "prefer
containment to inheritance".

goran.
From: Russ on
Thanks Joe (and Goran) for the help. I must have looked at those
declarations 50 times - and still did not see that I had somehow
dropped the const from the operator== and operator!= functions.

Of course it works now.

Thanks again, Russ


On Thu, 12 Nov 2009 23:34:28 -0500, Joseph M. Newcomer
<newcomer(a)flounder.com> wrote:

>See below...
>On Thu, 12 Nov 2009 17:46:46 -0500, Russ <russk2t(a)comcast.net> wrote:
>
>>Hi all. I must be doing something wrong but cannot figure it out. I
>>have a data class and a list class, in an extension DLL, declared like
>>this:
>>
>>>#define DllExport __declspec (dllexport)
>>
>>>class DllExport CRate : public CObject {
>>>public:
>>> DECLARE_SERIAL (CRate)
>>> CRate () { m_Rate = 0; }
>>> CRate (const CRate &in) { *this = in; }
>>>
>>> const CRate& operator= (const CRate& in)
>>> { m_Rate = in.m_Rate; m_Date = in.m_Date; return *this; }
>>>
>>> bool operator== (const CRate& in);
>****
> bool operator==(const CRate & in) const;
>****
>>> bool operator!= (const CRate& in) { return ! (*this == in); }
>****
> bool operator != (const CRate & in) const {return !(*this == in); }
>****
>>>
>>> virtual void Serialize (CArchive& Ar);
>>>
>>> double m_Rate;
>>> CString m_Date;
>>>};
>>
>>
>>>class DllExport CRateList : public CList <CRate, CRate&> {
>>>public:
>>> DECLARE_SERIAL (CRateList)
>>>
>>> double GetRate () const { return GetHead ().m_Rate; }
>>> double GetRate (const CString &da) const;
>>> void SetRate (const double& d, const CString &da);
>>>
>>> const CRateList& operator= (const CRateList& in);
>>>
>>> bool operator== (const CRateList& in);
>>> bool operator!= (const CRateList& in)
>>> { return ! (*this == in); }
>>>};
>>
>>The implementation for serialization looks like this:
>>
>>>IMPLEMENT_SERIAL (CRate, CObject, 1)
>>>IMPLEMENT_SERIAL (CRateList, CList, 1)
>>
>>
>>If I leave DllExport out of the class declarations, everything
>>compiles ok. It is still ok with DllExport only in the CRate class.
>>But when I put DllExport in the CRateList class, I get a compile error
>>like this:
>>
>> "error C2678: binary '==' : no operator found which takes a left-hand
>>operand of type 'const CRate' (or there is no acceptable conversion)"
>>
>>This error is attributed to the last line of a helper function called
>>CompareElements that looks like this (from afxtempl.h):
>>
>>>template<class TYPE, class ARG_TYPE>
>>>BOOL AFXAPI CompareElements(const TYPE* pElement1, const ARG_TYPE* pElement2)
>>>{
>>> ENSURE(pElement1 != NULL && pElement2 != NULL);
>>> ASSERT(AfxIsValidAddress(pElement1, sizeof(TYPE), FALSE));
>>> ASSERT(AfxIsValidAddress(pElement2, sizeof(ARG_TYPE), FALSE));
>>>
>>> return *pElement1 == *pElement2;
>>>}
>>
>>
>>As far as I can find, that helper is only called from CList::Find
>>function, which I am not using... And anyway I cannot figure out why
>>this only happens when I use dllexport.
>>
>>Help??
>>
>>Thanks, Russ
>Joseph M. Newcomer [MVP]
>email: newcomer(a)flounder.com
>Web: http://www.flounder.com
>MVP Tips: http://www.flounder.com/mvp_tips.htm