2

我正在用 C++/CLI (VS2010) 为第三方非托管库编写一个托管包装器。在代码中,我有一个如下所示的方法:

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

“nullptr”产生以下错误:

错误 C2446:“!=”:没有从“int”转换为“UnitStateChangedEventHandler ^”

编译器似乎将“nullptr”的任何使用视为“int”,即使是这样简单的事情:

Object^ temp = nullptr;

我读过的所有内容都表明编译器会自行解决,但似乎并非如此。是否有我缺少的设置(/clr 或 #pragma managed 除外)?

4

2 回答 2

3

没有 C++11 编译器的人写道

#define nullptr (0)

在头文件的某个地方?

(通常的宏是#define NULL (0)


这当然是被禁止的。

标准第 17.6.4.3.1 节,禁止使用关键字作为宏名称 C++11 关键字列表(标准中的表 4)

于 2012-06-25T20:58:59.527 回答
2

看起来您正试图触发一个事件。

在 C# 中,有一个标准的习惯用法用于触发事件,同时防止空引用异常和多线程修改:

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

看起来您正试图在 C++/CLI 中重新创建它,但这是不必要的。在 C++/CLI 中,一个事件将发出三个“内部方法”(这是它们的正确名称吗?),分别称为addremoveraise. 在 C# 中,它只创建add并且remove没有显式的 raise,这就是为什么我们必须一遍又一遍地编写该代码块的原因。

这是在 C++/CLI 中定义的事件,以及 .NET Reflector 在反编译时看到的内容:

// 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);
            }
        }
    }
}

内部raise方法正在为您进行空值检查,因此您可以跳过它,直接触发事件而不进行检查。

if(oldState != _state)
    this->UnitStateChanged(this, gcnew UnitStateChangedEventArgs(oldState, _state));
于 2012-06-25T21:37:05.203 回答