2
votes

I am writing a managed wrapper in C++/CLI (VS2010) for a third-party unmanaged library. In the code, I have a method that looks like this:

if(oldState != _state && UnitStateChanged != nullptr)
    UnitStateChanged(this, gcnew UnitStateChangedEventArgs(oldState, _state));

The "nullptr" generates the following error:

error C2446: '!=' : no conversion from 'int' to 'UnitStateChangedEventHandler ^'

The compiler seems to treat any use of "nullptr" as an "int", even on something as simple as this:

Object^ temp = nullptr;

Everything i've read indicates that the compiler will figure it out on it's own, but that doesn't seem to be the case. Is there a setting that I'm missing (other than /clr or #pragma managed)?

2
It would help if you could give the smallest "full" program that displayed the error so we could build and see for ourselves.Matt Smith

2 Answers

3
votes

Someone without a C++11 compiler wrote

#define nullptr (0)

somewhere in a header file?

(The usual macro is #define NULL (0))


This is, of course, forbidden.

Standard section 17.6.4.3.1, forbidden using keywords as macro nameslist of C++11 keywords (Table 4 from the Standard)

2
votes

It looks like you're trying to fire an event.

In C#, there's a standard idiom for firing an event while protecting against null reference exceptions and multithreading modification:

// C#
EventHandler handler = this.MyEvent;
if(handler != null)
    handler(this, new EventArgs(foo));

It looks like you're trying to re-create that in C++/CLI, but it's unnecessary. In C++/CLI, an event will emit three 'inner methods' (is that the proper name for them?) called add, remove, and raise. In C#, it creates add and remove only, no explicit raise, which is why we have to write that block of code over and over.

Here's an event defined in C++/CLI, and what .NET Reflector sees when it decompiles it:

// C++/CLI:
public ref class Test
{
public:
    event EventHandler^ MyEvent;
};


// Decompiled to C#:
public class Test
{
    // Fields
    private EventHandler <backing_store>MyEvent;

    // Events
    public event EventHandler MyEvent
    {
        [MethodImpl(MethodImplOptions.Synchronized)] add
        {
            this.<backing_store>MyEvent = (EventHandler) Delegate.Combine(this.<backing_store>MyEvent, value);
        }
        [MethodImpl(MethodImplOptions.Synchronized)] remove
        {
            this.<backing_store>MyEvent = (EventHandler) Delegate.Remove(this.<backing_store>MyEvent, value);
        }
        raise
        {
            EventHandler <tmp> = null;
            <tmp> = this.<backing_store>MyEvent;
            if (<tmp> != null)
            {
                <tmp>(value0, value1);
            }
        }
    }
}

The raise inner method is doing the null check for you, so you can skip doing it, and just fire the event without checking.

if(oldState != _state)
    this->UnitStateChanged(this, gcnew UnitStateChangedEventArgs(oldState, _state));