4

CコードからRに(外部Rを使用して)関数へのポインターを渡し、Rからその関数を呼び出した後はどうすればよいですか?

何かのようなもの:

C:

typedef void (* FunctionPtr)();
SEXP ans;
PROTECT(ans = /* ?some code? */);
R_tryEval(ans, R_GlobalEnv, NULL);
UNPROTECT(1);

R:

callback_function()

編集: @RomainFrancoisの投稿は非常に役に立ちました。
myappコード:

namespace
{
    void callback()
    {
        std::cout << "callback\n" << std::flush;
    }
}
class Worker
{
public:
/*...*/
    void initialize(argc, argv)
    {
       Rf_initEmbeddedR(argc, argv);

        SEXP ans, val;
        typedef void (* FunctionPtr)();

        PROTECT(ans = Rf_lang2(Rf_install("source"), Rf_mkString("script.R")));
        R_tryEval(ans, R_GlobalEnv, NULL);
        UNPROTECT(1);

        PROTECT(val = Rf_ScalarInteger((int)(&callback)));
        /* pass the address of the pointer to a function */
        PROTECT(ans = Rf_lang2(Rf_install("setCallback"), val));
        R_tryEval(ans, R_GlobalEnv, NULL);
        UNPROTECT(2);
    }
    void uninitialize()
    {
        Rf_endEmbeddedR(0);
    }
};

Rおよび
Rcppscript.R

###################
sourceCpp("utils.cpp")
###################
callback <- function()
{
  callCallback()
}

utils.cpp

#include <Rcpp.h>

using namespace Rcpp;

typedef void (* Callback)();
static Callback spCallback = 0;

// [[Rcpp::export]]
void callCallback()
{
  if (spCallback) {
    spCallback();
  } else {
    Rprintf("ERROR: callback is not set");
  }
}
// [[Rcpp::export]]
void setCallback(const int address)
{
  spPlaceOrder = (Callback)address;
}
4

3 に答える 3

6

外部ポインタはあなたが探しているものです。それらは、任意のデータ構造へのポインタをカプセル化することを意味します。ここではデータという単語が重要であり、関数ポインターは別の獣です。C++とを使用したい場合Rcppは、関数ポインタをカプセル化する小さなクラスを作成することをお勧めします。

typedef void (* FunctionPtr)();
class FunctionPointer {
  FunctionPtr ptr;
public:
    FunctionPointer( FunctionPtr ptr_) : ptr(ptr_){}
} ;

次に、:を作成しXPtr<FunctionPointer>ます

#include <Rcpp.h>
using namespace Rcpp ;

// your callback function
void callback(){
    Rprintf( "hello from callback\n" ) ;
}

// The function that creates an external pointer to your 
// callback
// [[Rcpp::export]]
XPtr<FunctionPointer> create_ptr(){
    return XPtr<FunctionPointer>( new FunctionPointer(callback) );
}

// The function that invokes the callback
// [[Rcpp::export]]
void invokeCallback( XPtr<FunctionPointer> callback){
    callback->ptr() ;
}

R側では、たとえば字句スコープを使用して、外部ポインターをR関数にラップできます。

callback <- local( {
    ptr <- create_ptr()
    function(){
        invokeCallback( ptr )
        invisible(NULL)
    } 
} )
callback()
于 2012-12-17T07:51:10.413 に答える
4

もう 1 つの方法は、InternalFunctionクラスを で使用することRcppです。

#include <Rcpp.h>
using namespace Rcpp ;

void callback(){
    Rprintf( "hello from calback\n" ) ;    
}

// [[Rcpp::export]]
InternalFunction get_callback(){
    return InternalFunction(callback) ;    
}

実装は、他の回答で説明したものと似ています。R 側の処理は次のように行われRcppます。

callback <- get_callback()
callback()
于 2012-12-17T08:45:21.130 に答える
0

最初にライブラリをロードします。

dyn.load("yourDLL.dll")

次に使用します。

R に読み込まれたコンパイル済みコードを呼び出す関数。

R FFIを見る

編集:

最初に C コードをコンパイルします。Windows では次のようになりますが、他の OS でも同様です。

gcc mylib.c -shared -o mylib.dll

そしてRで:

dyn.load("mylib.dll")     
tmp1  <- as.raw(rep(0,4))   # 4 bytes to be sent to the function's argument
tmp2<-.C("yourFunctionName", tmp1)   # tmp2 now has the data returned by the func

C++ (c では​​ない) では、関数名はマングルされた名前でなければならないことに注意してください

于 2012-12-16T19:52:08.983 に答える