简体   繁体   English

不能伪造来自 c++ 的托管回调(不能通过 static_cast 从 'void (GenFlowcacheTests::*)(int)' 转换为 'void(*)(int)')

[英]cannot fake a managed callback from c++ (cannot cast from 'void (GenFlowcacheTests::*)(int)' to 'void(*)(int)' via static_cast)

I define a pointer to a managed function with:我定义了一个指向托管 function 的指针:

typedef void(__stdcall* CounterCallback)(int count);

then I'll define a c++ method:然后我将定义一个 c++ 方法:

void CBSpline::GenFlowcache(/*few irrelevant parameters*/, CounterCallback func)
{/*instructions*/}

And in a unit test, I want to test GenFlowcache with a native function.在单元测试中,我想用原生 function 测试GenFlowcache

int _flowCount{};
auto Increment(int value) -> void { _flowCount = value; }

TEST_METHOD(Gen_CallbackTest)
{
    // ...
    sut.GenFlowcache(/**/, static_cast<CounterCallback>(GenFlowcacheTests::Increment));
}

But I cannot find a way to cast the method:但我找不到转换方法的方法:

cannot cast from 'void (GenFlowcacheTests::*)(int)' to 'void(*)(int)' via static_cast无法通过 static_cast 从 'void (GenFlowcacheTests::*)(int)' 转换为 'void(*)(int)'

( Compiler Error C2440 ) 编译器错误 C2440

How can I pass a native function (method, lambda etc) as CounterCallback ?如何将本机 function (方法,lambda 等)作为CounterCallback传递?

It is not useful for the problem, but the managed part is as such:它对问题没有用,但托管部分是这样的:

public delegate void CounterCallback(int value);

public static class CBSplines
{
    [DllImport("CubicBSplines.dll", CallingConvention = CallingConvention.StdCall)]
    internal static extern unsafe void GenFlowcache(IntPtr p, BroxParam* broxParam, IntPtr sourceDir, IntPtr targetDir, CounterCallback counter);
}

Then in a managed class:然后在托管 class 中:

private CounterCallback _counter;

public unsafe void GenerateFlowcache(BroxParam parameters, string sourceDir, string targetLocalDir)
{
    if (_counter is null)
        _counter = CounterUpdated;
    if (!Directory.Exists(targetLocalDir))
        Directory.CreateDirectory(targetLocalDir);
    var strSrcDir = Marshal.StringToHGlobalAuto(sourceDir);
    var strTgtDir = Marshal.StringToHGlobalAuto(targetLocalDir);
    CBSplines.GenFlowcache(_ptr, &parameters, strSrcDir, strTgtDir, _counter);
    Marshal.FreeHGlobal(strSrcDir);
    Marshal.FreeHGlobal(strTgtDir);
}

protected void CounterUpdated(int value) => FlowcacheCounter = value;

And back in native:回到本机:

#ifndef Pinvoke
#define Pinvoke extern "C" __declspec(dllexport)
#endif

Pinvoke auto GenFlowcache(CBSpline* p, BroxParam* param, const wchar_t* sourceDir, const wchar_t* targetDir, CounterCallback func)
-> void { p->GenFlowcache(param, sourceDir, targetDir, func); }

As pointed by john:正如约翰所指出的:

You can pass a function or static method typed void(int) you can also pass a non-capturing lambda with the same signature, and that's it.您可以传递 function 或 static 方法类型void(int)您也可以传递具有相同签名的非捕获 lambda ,并且You can't pass a class method however it is typed您不能通过 class 方法,但是它是键入的

I can pass a global function:我可以通过一个全局function:

int _flowCount{};
auto Increment(int value) -> void { _flowCount = value; }

that will be passed in the test method:将在测试方法中通过:

sut.GenFlowcache(/**/, (CounterCallback)Increment);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM