Tim
Tim

Reputation: 7474

Template for class returning elements of Rcpp::Vector<RTYPE>

Consider the following class that does absolutely nothing:

class MyNumVec
{
  private:
    const NumericVector& x;
  public:
    MyNumVec(const NumericVector& y) : x(y) {}
    double operator[](int i) const { // here
      return x[i];
    }
    operator NumericVector() const { return x; }
};

I would like to make it more general and use template for it so that I'll be working with any Vector<RTYPE> instead of numeric vectors only, but the problem is the line marked by comment since I must declare output type. I tried using auto type from C++11, but it doesn't work ("'auto' return without trailing return type"). How can this be translated to template working with Vector of any type?

Upvotes: 1

Views: 403

Answers (2)

nrussell
nrussell

Reputation: 18612

If you need to stick to C++98, the usual idiom is to use an integer template parameter to represent the different SEXPTYPEs. When dealing with Rcpp::*Vector (or Rcpp::*Matrix) you are typically only concerned with 5 of these:

# Integer Value SEXPTYPE  R Vector     Rcpp Vector
#            10   LGLSXP   logical   LogicalVector
#            13   INTSXP   integer   IntegerVector
#            14  REALSXP   numeric   NumericVector
#            15  CPLXSXP   complex   ComplexVector
#            16   STRSXP character CharacterVector

Having done this, there are standard metaprogramming tools for commonly needed transformations in the Rcpp::traits namespace:

  • SEXPTYPE -> POD¹ type: storage_type
    • Rcpp::traits::storage_type<REALSXP>::type -> double
    • Rcpp::traits::storage_type<INTSXP>::type -> int
    • etc.
  • POD¹ type -> SEXPTYPE: r_sexptype_traits
    • Rcpp::traits::r_sexptype_traits<double>::rtype -> 14 (REALSXP)
    • Rcpp::traits::r_sexptype_traits<int>::rtype -> 13 (INTSXP)
    • etc.

¹storage_type<STRSXP>::type yields SEXP (specifically, a CHARSXP), and while technically a POD type, it differs from the other simple vector types in that its atomic unit is an opaque pointer (a SEXP), and not, e.g. a const char* or std::string as might be expected.


An uninteresting example, using RCPP_RETURN_VECTOR for conciseness:

#include <Rcpp.h>

template <int RTYPE>
class MyNumVec {
public:
    typedef Rcpp::Vector<RTYPE> vec_t;
    typedef typename Rcpp::traits::storage_type<RTYPE>::type storage_t;

private:
    const vec_t& x;

public:
    MyNumVec(const vec_t& y)
        : x(y)
    {}

    storage_t operator[](int i) const
    { return x[i]; }

    operator vec_t() const
    { return x; }
};

template <int RTYPE>
Rcpp::Vector<RTYPE> get_first_elem_impl(const Rcpp::Vector<RTYPE>& vec)
{
    MyNumVec<RTYPE> tmp(vec);
    return Rcpp::Vector<RTYPE>::create(tmp[0]);
}

// [[Rcpp::export]]
Rcpp::RObject get_first_elem(Rcpp::RObject x) {
    RCPP_RETURN_VECTOR(get_first_elem_impl, x);
}

get_first_elem(c(TRUE, TRUE, FALSE, TRUE, FALSE))
# [1] TRUE

get_first_elem(1L:5L)
# [1] 1

get_first_elem(1:5 + 0.5)
# [1] 1.5

get_first_elem(1:5 + 2i)
# [1] 1+2i

get_first_elem(letters[1:5])
# [1] "a"

Upvotes: 7

Vittorio Romeo
Vittorio Romeo

Reputation: 93334

auto return type deduction without a trailing return type is a C++14 language feature. In C++11, you can use auto as long as you add a trailing return type:

auto operator[](int i) const -> decltype(x[i]) { 
    return x[i];
}

In the code above, auto will be "replaced" with the type of x[i].

Upvotes: 3

Related Questions