Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何共享C++;R包之间基于Rcpp的库中的函数?_C++_R_Rcpp - Fatal编程技术网

C++ 如何共享C++;R包之间基于Rcpp的库中的函数?

C++ 如何共享C++;R包之间基于Rcpp的库中的函数?,c++,r,rcpp,C++,R,Rcpp,我正在Rcpp中开发一个简单的库,用于构建哈夫曼树。它有一个工作的R接口,我可以从其他包调用,但是我也希望直接调用C++函数,在我开发的其他基于RCPP的包中,用C++代码调用。 我已经知道了如何将第一个包的头放在inst/include目录中,以便它在第二个包中可用。但是,当在第二个包的命名空间< /C>文件中调用 USEDYLYB时,加载它调用第一个包中的函数的C++代码,对于我正在使用的函数,我得到了一个未定义的符号错误。我将第一个包列在第二个包的说明文件中的导入,依赖于,以及链接到 这是

我正在Rcpp中开发一个简单的库,用于构建哈夫曼树。它有一个工作的R接口,我可以从其他包调用,但是我也希望直接调用C++函数,在我开发的其他基于RCPP的包中,用C++代码调用。 我已经知道了如何将第一个包的头放在
inst/include
目录中,以便它在第二个包中可用。但是,当在第二个包的命名空间< /C>文件中调用<代码> USEDYLYB时,加载它调用第一个包中的函数的C++代码,对于我正在使用的函数,我得到了一个未定义的符号错误。我将第一个包列在第二个包的
说明
文件中的
导入
依赖于
,以及
链接到

这是我第一次尝试使用任何非基于R的包,我通过Rstudio的“Build&Reload”命令进行所有开发,并在创建包以生成初始目录结构时使用了“Package w/Rcpp”选项。

是的,链接步骤比较困难,但仍然可行

例如,查看RcppXts包如何导入xts包导出的符号。这一切都相当乏味


我认为Kevin在他的Kmisc软件包中有一些必要注册步骤的助手。我一直想阅读这些内容,但还不需要它们/还没有时间。

在R中这样做的一般机制是通过
R\u registercallable
R\u GetCCallable
使函数指针可用。有关示例,请参见

这意味着符号是根据需要动态解析的——实际上不需要“链接”到另一个包本身;您只需要标题,以便稍后在执行代码时可以正确解析符号。请注意,
LinkingTo:
字段实际上是一个用词不当的字段——它只提供标题,实际上并没有将您链接到(为该)包生成的库

谢天谢地,这可以通过属性实现自动化,该属性本质上自动生成
RcppExports.cpp
中的
R\u registercallable
入口点,并在生成的头文件中使用
R\u GetCCallable
提供包装函数

例如,假设我有一个名为
rcppinertfaces
的愚蠢包,它在
src/test.cpp
中包含这个包(带有
说明
中包含
Rcpp
包括:
链接到:
)。请注意<代码> /[[RCPP::接口(r,CPP)] < /COD>注释,该信号向<代码> Rcpp <代码> >该文件应同时得到R导出和C++头输出。< /P>
// [[Rcpp::interfaces(r, cpp)]]

#include <Rcpp.h>

// [[Rcpp::export]]
void hello() {
    Rcpp::Rcout << "Hello!\n";
}
注意,早期的大部分内容都是样板文件,可以确保函数的异常安全版本是可调用的;最后,您基本上拥有了为其他包注册可调用函数的机制。在
inst/include/rcppineterfaces\u RcppExports.h
中,我们有:

// This file was generated by Rcpp::compileAttributes
// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393

#ifndef __RcppInterfaces_RcppExports_h__
#define __RcppInterfaces_RcppExports_h__

#include <Rcpp.h>

namespace RcppInterfaces {

    using namespace Rcpp;

    namespace {
        void validateSignature(const char* sig) {
            Rcpp::Function require = Rcpp::Environment::base_env()["require"];
            require("RcppInterfaces", Rcpp::Named("quietly") = true);
            typedef int(*Ptr_validate)(const char*);
            static Ptr_validate p_validate = (Ptr_validate)
                R_GetCCallable("RcppInterfaces", "RcppInterfaces_RcppExport_validate");
            if (!p_validate(sig)) {
                throw Rcpp::function_not_exported(
                    "C++ function with signature '" + std::string(sig) + "' not found in RcppInterfaces");
            }
        }
    }

    inline void hello() {
        typedef SEXP(*Ptr_hello)();
        static Ptr_hello p_hello = NULL;
        if (p_hello == NULL) {
            validateSignature("void(*hello)()");
            p_hello = (Ptr_hello)R_GetCCallable("RcppInterfaces", "RcppInterfaces_hello");
        }
        RObject __result;
        {
            RNGScope __rngScope;
            __result = p_hello();
        }
        if (__result.inherits("interrupted-error"))
            throw Rcpp::internal::InterruptedException();
        if (__result.inherits("try-error"))
            throw Rcpp::exception(as<std::string>(__result).c_str());
        return Rcpp::as<void >(__result);
    }

}

#endif // __RcppInterfaces_RcppExports_h__

在他们的代码中,我们只是使用R自己的机制自动确保在运行时查找和使用函数指针(安全!)。

Kevin对
R\u RegisterCallable
R\u GetCCallable
的精彩描述。就我个人而言,我认为应该将所有可供您的包或其他包使用的代码都放在头文件中。这就不那么脆弱了

谢谢你的指点;当我把它全部整理出来时,我会列出一个简短的例子。另外,感谢Rcpp:在这种情况下,
Kmisc
只是自动注册“本机例程”,例如。但我最近在Hadley那里发现,仅仅在
名称空间中编写
useDynLib(,)
实际上是等效的……可移植的?这将是一个巨大的帮助。我不知道C级函数注册,所以我只使用
命名空间中的
useDynLib()
完成了注册。似乎在跨平台工作,并受到Cran的祝福。在
// This file was generated by Rcpp::compileAttributes
// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393

#ifndef __RcppInterfaces_RcppExports_h__
#define __RcppInterfaces_RcppExports_h__

#include <Rcpp.h>

namespace RcppInterfaces {

    using namespace Rcpp;

    namespace {
        void validateSignature(const char* sig) {
            Rcpp::Function require = Rcpp::Environment::base_env()["require"];
            require("RcppInterfaces", Rcpp::Named("quietly") = true);
            typedef int(*Ptr_validate)(const char*);
            static Ptr_validate p_validate = (Ptr_validate)
                R_GetCCallable("RcppInterfaces", "RcppInterfaces_RcppExport_validate");
            if (!p_validate(sig)) {
                throw Rcpp::function_not_exported(
                    "C++ function with signature '" + std::string(sig) + "' not found in RcppInterfaces");
            }
        }
    }

    inline void hello() {
        typedef SEXP(*Ptr_hello)();
        static Ptr_hello p_hello = NULL;
        if (p_hello == NULL) {
            validateSignature("void(*hello)()");
            p_hello = (Ptr_hello)R_GetCCallable("RcppInterfaces", "RcppInterfaces_hello");
        }
        RObject __result;
        {
            RNGScope __rngScope;
            __result = p_hello();
        }
        if (__result.inherits("interrupted-error"))
            throw Rcpp::internal::InterruptedException();
        if (__result.inherits("try-error"))
            throw Rcpp::exception(as<std::string>(__result).c_str());
        return Rcpp::as<void >(__result);
    }

}

#endif // __RcppInterfaces_RcppExports_h__
RcppInterfaces::hello()