对工作程序中自定义函数的未定义引用(C ++和RcppParallel)

时间:2017-04-20 06:21:22

标签: c++ r rcpp rcppparallel

我是C ++编程的新手,试图通过R试验Rcpp。 我创建了一个函数来从字符串中生成所有可能的k-mers。它在串行形式中运行良好:

#include <Rcpp.h>
#include <string>
#include <iostream>
#include <ctime>
// using namespace Rcpp;

// [[Rcpp::export]]
std::vector< std::string > cpp_kmer( std::string s, int k ){
  std::vector< std::string > kmers;
  int seq_loop_size = s.length() - k+1;
  for ( int z=0; z < seq_loop_size; z++ ) {
    std::string  kmer;
    kmer = s.substr( z, k );
    kmers.push_back( kmer ) ;
  }
  return kmers;
}

但是,当我尝试在并行实现中使用此函数(使用RcppParallel)时,使用以下代码:

#include <Rcpp.h>
#include <string>
#include <iostream>
#include <ctime>
using namespace Rcpp;

// [[Rcpp::depends(RcppParallel)]]
#include <RcppParallel.h>
using namespace RcppParallel;

struct p_cpp_kmer : public Worker {
  // input string
  std::vector< std::string > seqs;
  int k;
  std::vector< std::string > cpp_kmer( std::string s, int k );
  // destination list
  List output;
  std::string
    sub_s;
  // initialize with source and destination
  p_cpp_kmer(std::vector< std::string > seqs, int k, List output) 
    : seqs(seqs), k(k), output(output) {}

  // calculate k-mers for the range of sequences requested
  void operator()(std::size_t begin, std::size_t end) {
    for (std::size_t i = begin; i < end; i++)
      sub_s = seqs[i];
      cpp_kmer(sub_s, k);
  }
};

// [[Rcpp::export]]
List par_cpp_kmer(std::vector< std::string > seqs, int k, bool v){
  // allocate output list 
  List outpar(num_seqs);
  int num_seqs = seqs.size();
  // p_cpp_kmer functor (pass input and output matrixes)
  p_cpp_kmer par_kmer(seqs, k, outpar);
  parallelFor(0, num_seqs, par_kmer);
  return wrap(outpar);
}

std::vector< std::string > cpp_kmer( std::string s, int k ){
  std::vector< std::string > kmers;
  int seq_loop_size = s.length() - k+1;
  for ( int z=0; z < seq_loop_size; z++ ) {
    std::string  kmer;
    kmer = s.substr( z, k );
    kmers.push_back( kmer ) ;
  }
  return kmers;
}

无法编译,给出了:对p_cpp_kmer :: cpp_kmer(std :: string,int)&#39; 错误的未定义引用。

我知道它与声明/引用cpp_kmer有关,但我无法弄清楚在哪里/如何做到这一点(由于我缺乏C ++知识)。

非常感谢你。

2 个答案:

答案 0 :(得分:2)

您的p_cpp_kmer结构声明了cpp_kmer方法但从未定义过,会发生什么。相反,后面定义的是自由函数cpp_kmer

您声明此方法

std::vector< std::string > cpp_kmer( std::string s, int k );

您似乎想要使用它:

void operator()(std::size_t begin, std::size_t end) {
  for (std::size_t i = begin; i < end; i++)
    sub_s = seqs[i];
    cpp_kmer(sub_s, k);
}

但你可以在这里定义自由函数cpp_kmer

std::vector< std::string > cpp_kmer( std::string s, int k ){
  std::vector< std::string > kmers;
  int seq_loop_size = s.length() - k+1;
  for ( int z=0; z < seq_loop_size; z++ ) {
    std::string  kmer;
    kmer = s.substr( z, k );
    kmers.push_back( kmer ) ;
  }
  return kmers;
}

您可以删除结构中cpp_kmer方法的定义,以便使用自由函数,或者实际定义它。

代码还有其他问题:

  • operator()中,您放弃了结果。我想你的意思是output[i] = cpp_kmer(sub_s, k);

  • 即使您执行上述操作,代码也不安全,因为output[i] = cpp_kmer(sub_s, k);分配R对象(每个单独的R字符串和字符串向量),这在单独的线程中不会发生。

如果您确实想要并行执行此操作,则需要确保不在工作程序中分配任何R对象。

此外,考虑使用C ++ 11和基础RcppParallel的tbb库时,编写并行代码要容易得多。例如:

#include <Rcpp.h>
#include <RcppParallel.h>

using namespace Rcpp;
using namespace RcppParallel;

// [[Rcpp::depends(RcppParallel)]]
// [[Rcpp::plugins(cpp11)]]

using string_vector = std::vector< std::string > ; 
using list_string_vector = std::vector<string_vector> ;

// [[Rcpp::export]]
list_string_vector par_cpp_kmer( string_vector  seqs, int k, bool v){
  int num_seqs = seqs.size() ;

  list_string_vector out(num_seqs) ;

  tbb::parallel_for( 0, num_seqs, 1, [&seqs,k,&out](int i){
    std::string& s = seqs[i] ;
    int seq_loop_size = s.length() - k+1;

    std::vector<std::string> vec(seq_loop_size) ;
    for ( int z=0; z < seq_loop_size; z++ ) {
      vec[z] = s.substr( z, k );
    }
    out[i] = vec ;

  }) ;
  return out ;
}

这假设可以在单独的线程中分配std::string

> par_cpp_kmer( c("foobar", "blabla"), 3 )
[[1]]
[1] "foo" "oob" "oba" "bar"

[[2]]
[1] "bla" "lab" "abl" "bla"

答案 1 :(得分:0)

对于不同的结构(或公共名称空间),您可能有using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.Configuration; using System.IO; using System.Collections; using SAIT_Electronics.Models; namespace SAIT_Electronics.Pages.Management { public partial class ManageProducts : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { ImagesFolder(); //check if the url contains an id parameter if (!string.IsNullOrWhiteSpace(Request.QueryString["id"])) { int id = Convert.ToInt32(Request.QueryString["id"]); FillPage(id); } } } protected void btnSubmit_Click(object sender, EventArgs e) { productmodel ProductModel = new productmodel(); Product product = CreateProduct(); //check if the url contains an id parameter if (!string.IsNullOrWhiteSpace(Request.QueryString["id"])) { //id exist -> update existing row int id = Convert.ToInt32(Request.QueryString["id"]); lblResults.Text = ProductModel.UpdateProduct(id, product); } else { //id does not exist -> create a new row lblResults.Text = ProductModel.InsertProduct(product); } } private void FillPage(int id) { // get selected products from db productmodel ProductModel = new productmodel(); Product product = ProductModel.GetProduct(id); //fill text boxes txtDescription.Text = product.Description; txtName.Text = product.Name; txtPrice.Text = product.Price.ToString(); //set dropdown list values ddImage.SelectedValue = product.Image; ddType.SelectedValue = product.TypeId.ToString(); } private void ImagesFolder() { try { //get all file paths //string[] images = Directroy.GetFiles(Server.MapPath("~/Images/Products/")); // string[] images = Server.MapPath(@"/Images/Products/"); string[] images = System.IO.Directory.GetFiles(Server.MapPath("~/Images/Products/")); // String images = new DirectoryInfo(@"D:\Desktop\Shoping\SAIT_Electronics\SAIT_Electronics\Images\Products\").Name; //string[] images = Directory.GetFiles(("~/D:/Desktop/Shoping/SAIT_Electronics/SAIT_Electronics/Images/Products/"), "*.xml"); //get all file names and add them to an arraylist ArrayList imageList = new ArrayList(); foreach (string image in images ) { string imageName = image.Substring(image.LastIndexOf(@"\", StringComparison.Ordinal) + 1); imageList.Add(imageName); } // set the array list as dropdwon views datasouce and refresh ddImage.DataSource = imageList; ddImage.AppendDataBoundItems = true; ddImage.DataBind(); } catch (Exception e) { lblResults.Text = e.ToString(); } } private Product CreateProduct() { Product product = new Product(); product.Name = txtName.Text; product.Price = Decimal.Parse(txtPrice.Text); product.TypeId = Convert.ToInt32(ddType.SelectedValue); product.Description = txtDescription.Text; product.Image = ddImage.SelectedValue; return product; } } }的实现,但是在结构cpp_kmer中缺少成员函数cpp_kmer的实现。您必须添加如下实现:

p_cpp_kmer