2017-04-20 104 views
1

我是C++编程的新手,尝试通过R来试验Rcpp。 我创建了一个函数来从字符串中产生所有可能的k-mers。它的工作原理以及在它的串行形式:未定义引用自定义函数(C++和RcppParallel)

#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)'错误。

我知道它与声明/引用cpp_kmer有关,但我无法找到适当的地方/如何做(因为我缺乏C++知识)。

非常感谢您提前。

回答

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" 
+0

非常感谢你,你的解决方案看起来很简单,但是当试图编译它时,我收到以下错误:'cpp_kmer_par_SO.cpp:10:7:错误:'string_vector'之前预期的嵌套名称说明符' cpp_kmer_par_SO.cpp :10:7:错误:'string_vector'尚未声明 cpp_kmer_par_SO.cpp:10:21:错误:预计';'在'='标记之前 和'list_string_vector'声明的类似错误。 我证实我可以使用[Rcpp gallery](http://gallery.rcpp.org/articles/first-steps-with-C++11/)中的示例编译其他C++ 11代码。 – IsoBar

+0

关于使代码“线程安全”,我试图使用RVector 方法,如[这里](https://rcppcore.github.io/RcppParallel/#safe_accessors)所述,但我不能'找到使用这个结构的字符串而不是数字的任何例子。 – IsoBar

+0

您使用'expected nested-name-specifier'指定的错误表明您可能没有完整的C++ 11实现。也许你可以使用一些'typedef'来代替。 –

0

对于不同的结构(或公共名称空间),您可能有一个针对cpp_kmer的实现,但是您的struct p_cpp_kmer缺少成员函数cpp_kmer的实现。你将需要添加一个实现,如:

std::vector<std::string> p_cpp_kmer::cpp_kmer(std::string s, int k) { 
    // your implementation goes here 
} 
+0

@StephanLechter,你的意思是移动cpp_kmer的p_cpp_kmer结构内部的整个实施? – IsoBar