Pasar la función de propiedad de delegado no estático como parámetro en C++/CLI

Hago una clase de interfaz en C++ para el reconocimiento de voz, estoy usando la API de Julius. http://julius.sourceforge.jp/en_index.php?q=index-en.html.

Bueno, mi clase tiene algunos eventos, estos eventos serán activados por la API de Julius. La API de Julius tiene la llamada de función callback_add con esta firma:

int callback_add (Recog *recog, int code, void(*func)(Recog *recog, void *data), void data)

Uso algunas funciones de 'proxy' para invocar los eventos y pasar estas funciones a callback_add.

Si el evento de propiedad es estático, funciona bien, pero si no es estático, dentro de la función de proxy, la propiedad no se reconoce.

Lo difícil es porque tengo que usar la función callback_add y no puedo modificar esto.

Aquí hay un resumen de la clase con 2 eventos (estático y no estático)

Encabezamiento

#ifndef FALAENGINE_H_
#define FALAENGINE_H_

#pragma once

extern "C"{
#include <julius/julius.h>
}

namespace FalaAPI {

    public ref class FalaEngine
    {
    public:
        FalaEngine();
        ~FalaEngine();

        // Events
        delegate void OnRecognizedDele(FalaAPI::RecoResult^ result);
        static property OnRecognizedDele^ OnRecognized;

        delegate void OnEngineStartDele();
        property OnEngineStartDele^ OnEngineStart;

    private:
        Recog *recog;
        Jconf *jconf;
    };
}

#endif /* FALAENGINE_H_*/

Fuente

#include "stdafx.h"

using System::String;
using System::Console;

#include "FalaEngine.h"
#include <windows.h>

namespace FalaAPI{
    void StartOnEngineStart()(Recog *recog, void * dummy){
        if(FalaEngine::OnEngineStart->GetInvocationList()->Length > 0)
            FalaEngine::OnEngineStart->Invoke();
    }

    void StartOnRecognized()(Recog *recog, void * dummy){
        if(FalaEngine::OnRecognized->GetInvocationList()->Length > 0)
            FalaEngine::OnRecognized->Invoke();
    }

    FalaEngine::FalaEngine(){
        recog = j_recog_new();
        jconf = j_jconf_new();

        //Julius callback Functions
        callback_add(recog, CALLBACK_EVENT_PROCESS_ONLINE, StartOnEngineStart, NULL);

        callback_add(recog, CALLBACK_RESULT, StartOnRecognized, NULL);
    }
}

El problema ocurre dentro de la función StartOnEngineStart:

error C2227: a la izquierda de '->GetInvocationList' debe apuntar a clase/estructura/unión/tipo genérico

preguntado el 30 de junio de 12 a las 15:06

1 Respuestas

Un miembro no estático existe por separado en cada instancia. No ha especificado qué instancia contiene el delegado que desea inspeccionar, solo ha especificado una clase (y puede haber muchas instancias).

Intenta usar el dummy parámetro para pasar su instancia. Pero tenga cuidado, porque el recolector de basura moverá los objetos a menos que los haya anclado, por lo que simplemente pasar la dirección no funcionará. Necesitas crear y pasar un GCHandle en lugar de. (Tenga cuidado de no filtrar el GCHandle, o su objeto nunca se liberará)


Algo como esto debería ser efectivo:

ref class FalaEngine;

struct EngineHandle
{
    gcroot<FalaEngine^> handle;
    EngineHandle(FalaEngine^ engine) : handle(engine) {}
};

public ref class FalaEngine
{
    clr_scoped_ptr<EngineHandle> callback_ptr;
public:
    FalaEngine();
    ~FalaEngine();

    // Events
    delegate void OnRecognizedDele(FalaAPI::RecoResult^ result);
    property OnRecognizedDele^ OnRecognized;


    delegate void OnEngineStartDele();
    property OnEngineStartDele^ OnEngineStart;

private:
    Recog *recog;
    Jconf *jconf;
};

void StartOnEngineStart(Recog *recog, void * dummy)
{
    FalaEngine^ that = static_cast<EngineHandle*>(dummy)->handle;
    that->OnEngineStart(); // C++/CLI already checks if the invocation list is empty
}


void StartOnRecognized(Recog *recog, void * dummy)
{
    FalaEngine^ that = static_cast<EngineHandle*>(dummy)->handle;
    that->OnRecognized(recog->get_result());
}

FalaEngine::FalaEngine()
    : callback_ptr(new EngineHandle(this))
{
    recog = j_recog_new();
    jconf = j_jconf_new();


    //Julius callback Functions
    callback_add(recog, CALLBACK_EVENT_PROCESS_ONLINE, StartOnEngineStart, callback_ptr.get());

    callback_add(recog, CALLBACK_RESULT, StartOnRecognized, callback_ptr.get());

}

La clr_scoped_ptr la clase está aquí. No hay muchos requisitos de licencia, pero asegúrese de seguirlos si lo usa.

Respondido 13 Abr '17, 13:04

Este es mi miedo. Estoy oxidado en C++, ahora trabajo con Java y C#. ¿Me pueden ayudar con una muestra? - Fabio Ávila

¿Crees que he usado un evento y ninguna propiedad? - Fabio Ávila

¿Cómo puedo pasar la instancia (esto), toh callback_add una vez que el parámetro de datos es nulo *? - Fabio Ávila

@Fabio: Con una clase nativa, es fácil, simplemente puede pasar el puntero al objeto y static_cast dentro de la devolución de llamada. Para un objeto administrado, lo mejor que puede hacer es crear una clase nativa con un gcroot dentro, y luego pase un puntero al objeto nativo. La devolución de llamada puede obtener el identificador administrado del objeto nativo. - ben voigt

@Fabio: agregué un ejemplo mayormente completo. - ben voigt

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.