能够引用函数但不是命名空间中的类

时间:2016-11-01 02:07:58

标签: r rcpp

我能够从命名空间引用函数,但不能引用类。这是名称空间文件 SeqLib / FermiAssembler.h"

#ifndef SEQLIB_FERMI_H
#define SEQLIB_FERMI_H

#include <string>
#include <cstdlib>
#include <iostream>

namespace SeqLib 
{

    void print_my_name(){ std::cout << "It's Crt" }
    class FermiAssembler {
    public:
        FermiAssembler();

        ~FermiAssembler();

        void AddReads(const BamRecordVector& brv);
    };
}

我可以致电print_my_name() via SeqLib::print_my_name(),但无法通过SeqLib::FermiAssembler f

引用FermiAssembler课程

这是我/src

中的C ++文件
#include <iostream>
#include <Rcpp.h>
#include "SeqLib/FermiAssembler.h"
using namespace std;

// [[Rcpp::export]]
void whats_my_name(){
     SeqLib::FermiAssembler f; 

这是包的结构

temp
  seqLib
  SeqLib
    src
      FermiAssembler.cpp
    SeqLib
      FermiAssembler.h
  headerFiles
    SeqLibCommon.h
  src
    hello_world.cpp
    Makevars which contains PKG_CXXFLAGS= -I../SeqLib

这是 FermiAssembler.cpp 定义的

 #include "SeqLib/FermiAssembler.h"
 #define MAG_MIN_NSR_COEF .1

 namespace SeqLib {
    FermiAssembler::~FermiAssembler() {
      ClearReads();
      ClearContigs();
    }
 }

错误消息为:Error in dyn.load(dllfile) :
unable to load shared object 'temp/seqLib/src/SeqLib.so':
temp/seqLib/src/SeqLib.so: undefined symbol: _ZN6SeqLib14FermiAssemblerD1Ev

更新我已将整个子模块移动到src文件夹中:

# temp
# |─── src 
#       |────SeqLib
#              |──────SeqLib 
#                        |────── FermiAssembler.h 
#              |──────src 
#                        |────── FermiAssembler.cpp

1 个答案:

答案 0 :(得分:3)

当您看到引用_ZN6SeqLib14FermiAssemblerD1Ev之类的错误时,第一步是通过名称解析器c++filt运行它,它应包含在任何Linux发行版中:

$ c++filt _ZN6SeqLib14FermiAssemblerD1Ev
# SeqLib::FermiAssembler::~FermiAssembler()

问题是,在您的标头文件中,声明了FermiAssembler的析构函数,但没有提供定义。你的选择是

  1. 完全删除声明。如果此类的析构函数没有做任何特殊操作,例如释放动态分配的内存或记录信息等,那么生成的默认析构函数应该没问题由编译器。但是,如果您提供如上所述的声明,则告诉编译器“此类的析构函数需要执行额外的操作,因此请不要为我生成一个。”
  2. 提供空定义 ~FermiAssembler() {}(请注意大括号,将其与声明区分开来)。这相当于使用编译器生成的析构函数,如上所述。
  3. 提供非空的定义在这个简单的示例中,FermiAssembler类不需要非默认的析构函数,但是为了演示的目的我们将在下面探讨此选项。
  4. 这是我将要使用的文件布局;您需要相应地调整#include路径等:

    tree example/
    
    # example/
    # ├── DESCRIPTION
    # ├── example.Rproj
    # ├── NAMESPACE
    # ├── R
    # │   └── RcppExports.R
    # └── src
    #     ├── demo.cpp
    #     ├── FermiAssembler.cpp
    #     ├── FermiAssembler.h
    #     └── RcppExports.cpp 
    

    标题FermiAssembler.h现在变为:

    #ifndef SEQLIB_FERMI_H
    #define SEQLIB_FERMI_H
    
    namespace SeqLib {
    
    class BamRecordVector;
    
    void print_my_name();
    
    class FermiAssembler {
    public:
        FermiAssembler();
    
        ~FermiAssembler();
    
        void AddReads(const BamRecordVector& brv);
    };
    
    } // SeqLib
    
    #endif // SEQLIB_FERMI_H
    

    请注意,我还将print_my_name转换为函数原型,因此还需要在相应的源文件中定义它。此外,您可以将之前的#include移动到源文件,因为此处不再需要它们:

    // FermiAssembler.cpp
    #include "FermiAssembler.h"
    #include <iostream>
    #include <Rcpp.h>
    
    namespace SeqLib {
    
    void print_my_name() {
        std::cout << "It's Crt";
    }
    
    FermiAssembler::FermiAssembler()
    {
        Rcpp::Rcout << "FermiAssembler constructor\n";
    }
    
    FermiAssembler::~FermiAssembler()
    {
        Rcpp::Rcout << "FermiAssembler destructor\n";
    }
    
    } // SeqLib
    

    最后,使用此类的文件:

    // demo.cpp
    #include "FermiAssembler.h"
    
    // [[Rcpp::export]]
    int whats_my_name() {
        SeqLib::FermiAssembler f;
    
        return 0;
    }
    

    在构建和安装软件包之后,它按预期工作:

    library(example)
    whats_my_name()
    # FermiAssembler constructor
    # FermiAssembler destructor
    # [1] 0
    

    更新关于“可以在顶级src/目录以外的地方拥有源文件吗?”的问题,是的,你可以,但我会通常建议不要这样做,因为它需要一个非常重要的Makevars文件。现在使用这种布局,

    tree example
    
    # example
    # ├── DESCRIPTION
    # ├── example.Rproj
    # ├── man
    # ├── NAMESPACE
    # ├── R
    # │   └── RcppExports.R
    # ├── SeqLib
    # │   ├── SeqLib
    # │   │   └── FermiAssembler.h
    # │   └── src
    # │       └── FermiAssembler.cpp
    # └── src
    #     ├── demo.cpp
    #     ├── Makevars
    #     └── RcppExports.cpp
    

    我们位于顶级src/目录( SeqLib/src)此Makevars

    PKG_CXXFLAGS= -I../SeqLib
    
    SOURCES = $(wildcard ../SeqLib/*/*.cpp *.cpp)
    OBJECTS = $(wildcard ../SeqLib/*/*.o *.o) $(SOURCES:.cpp=.o) 
    

    请注意,在上面的示例中,我们只是将所有目标文件编译到同一个共享库中。例如,如果您需要编译中间共享库或静态库并将它们链接到最终.so,那么期望您的Makevars变得更加混乱。

    重建和安装,

    library(example)
    whats_my_name()
    # FermiAssembler constructor
    # FermiAssembler destructor
    # [1] 0