为什么一个Rcpp::Function可以当boost::function使用,能在运行时自省吗?
Why can a Rcpp::Function be used as boost::function, and can it be introspected at runtime?
我有一个 vector<boost::function<void(void)>>
-- 本质上,一个类函数对象的向量。该向量包含一些 Rcpp::Function
个对象,以及一些 boost::function<void(void)>
个对象。
我有两个问题。首先,我不太明白这是怎么回事,因为据我所知,Rcpp::Function
不是 boost::function
的子 class。 vector如何存储这些class不相同的对象呢? (或者他们是否以某种方式共享 class?)
其次,更重要的是,我希望能够在运行时内省对象。我想迭代向量和 return 它的 Rcpp::List
表示:任何 Rcpp::Function
对象将被添加到列表中,任何 boost::function
对象将简单地表示为任意字符串,例如 "C++ function"
.
在下面的示例中,我有一个 C++ 函数 test
,它将 Rcpp::Function
作为输入并添加到向量中。它还向向量添加了一个 boost::function<void(void)>
。然后它遍历列表,执行每个函数。我还没有弄清楚的最后一部分是如何构建一个 List
,其中添加到列表的项目取决于每个项目的类型。这可能吗?
library(Rcpp)
cppFunction(
includes = '
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>
void cpp_message(std::string s) {
std::cerr << s << "\n";
}
',
code = '
Rcpp::List test(Rcpp::Function r_fn) {
std::vector<boost::function0<void> > fns;
// Add a Rcpp::Function to the vector
fns.push_back(r_fn);
// Add a boost::function<void(void)> to the vector
boost::function<void(void)> cpp_fn = boost::bind(&cpp_message, "bar");
fns.push_back(cpp_fn);
// Execute the functions to demonstrate the vector works
for (int i=0; i<fns.size(); i++) {
fns[i]();
}
// Create the List
Rcpp::List result;
for (int i=0; i<fns.size(); i++) {
// What I would like to do is something like:
// if (fns[i] is a Rcpp::Function) {
// result[i] = fns[i];
// } else {
// result[i] = "C++ function";
// }
}
return result;
}
',
depends = "BH"
)
test(function() message("foo"))
#> foo
#> bar
#> list()
(请注意,输出行的顺序可能因环境缓冲输出的方式而异,因此您可能会看到它以不同的顺序出现。)
How does the vector store these objects that don't have the same class?
好吧,不是 存储此类对象的向量(直接),而是向量中新创建的 boost::function
对象将存储实例。这个对象会怎么做?
一些简单的演示 class 说明了如何 可以 实现:
// first need a generic template allowing the Demo<void(void)> syntax
template <typename S>
class Demo;
// now specialising (otherwise, we'd need to instantiate Demo<void, void>)
template <typename R, typename ... PP>
class Demo<R(PP...)>
{
class Wrapper
{
public:
virtual ~Wrapper() { }
virtual R operator()(PP...) = 0;
};
template <typename T>
class SpecificWrapper : public Wrapper
{
T t;
public:
SpecificWrapper(T& t) : t(t) { };
virtual R operator()(PP...pp) { return t(pp...); }
};
// the trick: pointer to POLYMORPHIC type!
Wrapper* w;
public:
// be aware that this constructor deliberately is NOT explicit
template <typename T>
Demo(T& t) : w(new SpecificWrapper<T>(t)) { }
R operator()(PP...pp) { return (*w)(pp...); }
};
非显式构造函数允许隐式创建一个新的 Demo 对象:
Rcpp::Function r; // simplified just for demo!
std::vector<Demo<void(void)>> v;
v.push_back(r); // implicit call to non-explicit constructor! equivalent to:
v.push_back(Demo<void(void)>(r));
请注意,class 只是最低限度地实现(仅复制构造函数;可能还会添加移动构造函数和适当的赋值运算符),因为它仅用于演示目的。
I would like to be able to introspect the objects at runtime.
您正在寻找 std::function::target:
auto l = []() { std::cout << "demo" << std::endl; };
std::function<void(void)> f(l);
auto* pl = f.target<decltype(l)>();
if(pl)
(*pl)();
但这闻起来有点糟糕的设计,就像需要 dynamic_cast
(Demo
很可能会在它自己的 target
变体中的包装器指针上使用)。你为什么要拿回这个?难道你不想像处理所有功能一样,无论是否使用 Rcpp?
我有一个 vector<boost::function<void(void)>>
-- 本质上,一个类函数对象的向量。该向量包含一些 Rcpp::Function
个对象,以及一些 boost::function<void(void)>
个对象。
我有两个问题。首先,我不太明白这是怎么回事,因为据我所知,Rcpp::Function
不是 boost::function
的子 class。 vector如何存储这些class不相同的对象呢? (或者他们是否以某种方式共享 class?)
其次,更重要的是,我希望能够在运行时内省对象。我想迭代向量和 return 它的 Rcpp::List
表示:任何 Rcpp::Function
对象将被添加到列表中,任何 boost::function
对象将简单地表示为任意字符串,例如 "C++ function"
.
在下面的示例中,我有一个 C++ 函数 test
,它将 Rcpp::Function
作为输入并添加到向量中。它还向向量添加了一个 boost::function<void(void)>
。然后它遍历列表,执行每个函数。我还没有弄清楚的最后一部分是如何构建一个 List
,其中添加到列表的项目取决于每个项目的类型。这可能吗?
library(Rcpp)
cppFunction(
includes = '
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>
void cpp_message(std::string s) {
std::cerr << s << "\n";
}
',
code = '
Rcpp::List test(Rcpp::Function r_fn) {
std::vector<boost::function0<void> > fns;
// Add a Rcpp::Function to the vector
fns.push_back(r_fn);
// Add a boost::function<void(void)> to the vector
boost::function<void(void)> cpp_fn = boost::bind(&cpp_message, "bar");
fns.push_back(cpp_fn);
// Execute the functions to demonstrate the vector works
for (int i=0; i<fns.size(); i++) {
fns[i]();
}
// Create the List
Rcpp::List result;
for (int i=0; i<fns.size(); i++) {
// What I would like to do is something like:
// if (fns[i] is a Rcpp::Function) {
// result[i] = fns[i];
// } else {
// result[i] = "C++ function";
// }
}
return result;
}
',
depends = "BH"
)
test(function() message("foo"))
#> foo
#> bar
#> list()
(请注意,输出行的顺序可能因环境缓冲输出的方式而异,因此您可能会看到它以不同的顺序出现。)
How does the vector store these objects that don't have the same class?
好吧,不是 存储此类对象的向量(直接),而是向量中新创建的 boost::function
对象将存储实例。这个对象会怎么做?
一些简单的演示 class 说明了如何 可以 实现:
// first need a generic template allowing the Demo<void(void)> syntax
template <typename S>
class Demo;
// now specialising (otherwise, we'd need to instantiate Demo<void, void>)
template <typename R, typename ... PP>
class Demo<R(PP...)>
{
class Wrapper
{
public:
virtual ~Wrapper() { }
virtual R operator()(PP...) = 0;
};
template <typename T>
class SpecificWrapper : public Wrapper
{
T t;
public:
SpecificWrapper(T& t) : t(t) { };
virtual R operator()(PP...pp) { return t(pp...); }
};
// the trick: pointer to POLYMORPHIC type!
Wrapper* w;
public:
// be aware that this constructor deliberately is NOT explicit
template <typename T>
Demo(T& t) : w(new SpecificWrapper<T>(t)) { }
R operator()(PP...pp) { return (*w)(pp...); }
};
非显式构造函数允许隐式创建一个新的 Demo 对象:
Rcpp::Function r; // simplified just for demo!
std::vector<Demo<void(void)>> v;
v.push_back(r); // implicit call to non-explicit constructor! equivalent to:
v.push_back(Demo<void(void)>(r));
请注意,class 只是最低限度地实现(仅复制构造函数;可能还会添加移动构造函数和适当的赋值运算符),因为它仅用于演示目的。
I would like to be able to introspect the objects at runtime.
您正在寻找 std::function::target:
auto l = []() { std::cout << "demo" << std::endl; };
std::function<void(void)> f(l);
auto* pl = f.target<decltype(l)>();
if(pl)
(*pl)();
但这闻起来有点糟糕的设计,就像需要 dynamic_cast
(Demo
很可能会在它自己的 target
变体中的包装器指针上使用)。你为什么要拿回这个?难道你不想像处理所有功能一样,无论是否使用 Rcpp?