C++ 包装一个通用函数以获取它';从字符串中删除参数
我希望围绕一个通用函数t0f(T1,T2,T3…)自动创建一个包装器,它从堆栈上的字符串中提取该函数的参数(转换为适当的类型),并对返回值进行处理。如果我可以执行以下伪ish代码,我的理想结果将实现:C++ 包装一个通用函数以获取它';从字符串中删除参数,c++,variadic-templates,C++,Variadic Templates,我希望围绕一个通用函数t0f(T1,T2,T3…)自动创建一个包装器,它从堆栈上的字符串中提取该函数的参数(转换为适当的类型),并对返回值进行处理。如果我可以执行以下伪ish代码,我的理想结果将实现: #include <stack> std::stack<char*> argStack; std::stack<char*> retStack; int add(float a, float b){ return a+b; } int main(){
#include <stack>
std::stack<char*> argStack;
std::stack<char*> retStack;
int add(float a, float b){
return a+b;
}
int main(){
argStack.push((char*)"2");
argStack.push((char*)"5");
auto wrapped=funcWrap(add);
wrapped();
std::cout << retStack.top();
return 0;
}
#包括
std::stack argStack;
std::stack-retStack;
整数相加(浮点a,浮点b){
返回a+b;
}
int main(){
argStack.push((char*)“2”);
argStack.push((char*)“5”);
自动换行=自动换行(添加);
包裹的();
std::cout>convertedVar;
收益转换var;
}
模板结构funcWrap;
模板
struct funcWrap//专门用于typename=R(Args…)
{
使用funcType=Fn;
funcType*wrappedFunc;
funcWrap(funcType和inputFunc){
此->wrappedFunc=&inputFunc;
}
void运算符()(){
auto tup=std::make_tuple(getNextArg)。它只是使用所提供的tuple中包含的参数调用函数指针
我使用这个模式的一个更高级的版本已经有一段时间了(主要是为了自动生成一个接口来调试在arduino上运行的代码),它工作得很好,但它有两个主要的问题我正在努力解决:它是冗余的(因为我在包装过程中写了三次函数名),并且它对成员函数不起作用。是否可以解决此问题?似乎您的主要问题是构建函数对象。避免重复指定函数并涵盖成员函数的最简单方法是使用工厂函数推断相关类型。适当地重载此函数可以使区分普通函数和成员函数。我假设函数类型的重复使用是针对表示类型和签名类型实际上不同的函数对象
template <typename R, typename... A>
funcWrap<R(A...), R(*)(A...)>
wrap(R(*fun)(A...)) { // deal with functions
return funcWrap<R(A...), R(*)(A...)>(fun);
}
template <typename Signature, typename F>
funcWrap<Signature, F>
wrap(F&& f) { // deal with function objects
return funcWrap<Signature, F>(std::forward<F>(f));
}
template <typename R, typename S, typename... A>
funcWrap<R(S&, A...), R (S::*)(A...)>
wrap(R(S::*mem)(A...)) {
return funcWrap<R(S&, A...), R (S::*)(A...)>(mem);
}
您需要处理召唤合适对象来调用您的成员的问题,并且您可能需要函数包装器的一些专门化funcWrap
。此外,对于成员函数的情况,您可能需要为const
成员函数提供合适的重载。对于成员函数,指定当包装成员并适当捕获它时,对象被绑定。使用std::bind()
或lambda函数也可以使用函数对象的包装绑定成员函数,但这很可能需要指定签名,否则可以推断出签名
下面是一个使用C++11编译的完整演示,显示了使包装工作正常所需的所有位和位:
#include <iostream>
#include <sstream>
#include <stack>
#include <string>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <utility>
#include <cstddef>
// ----------------------------------------------------------------------------
template <typename T>
typename std::decay<T>::type makeArg(std::stack<std::string>& args) {
typename std::decay<T>::type rc;
if (args.empty() || !(std::istringstream(args.top()) >> rc)) {
throw std::runtime_error("can't create argument from '" + (args.empty()? "<empty>": args.top()) + "'");
}
args.pop();
return rc;
}
// ----------------------------------------------------------------------------
namespace util
{
template<typename T, T...>
struct integer_sequence {
};
template<std::size_t... I>
using index_sequence = integer_sequence<std::size_t, I...>;
template <typename T, std::size_t N, T... I>
struct integer_sequencer {
using type = typename integer_sequencer<T, N - 1, N - 1, I...>::type;
};
template <typename T, T... I>
struct integer_sequencer<T, 0, I...> {
using type = integer_sequence<T, I...>;
};
template<typename T, T N>
using make_integer_sequence = typename integer_sequencer<T, N>::type;
template<std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
template <typename F, typename T, std::size_t... I>
auto apply_aux(F&& fun, T&& tuple, index_sequence<I...>) -> decltype(fun(std::get<I>(tuple)...)) {
return fun(std::get<I>(tuple)...);
}
template <typename F, typename T>
auto apply(F&& f, T&& t)
-> decltype(apply_aux(std::forward<F>(f), std::forward<T>(t), make_index_sequence<std::tuple_size<typename std::decay<T>::type>::value>())) {
return apply_aux(std::forward<F>(f), std::forward<T>(t), make_index_sequence<std::tuple_size<typename std::decay<T>::type>::value>());
}
}
// ----------------------------------------------------------------------------
template <typename S, typename F> class funcWrap;
template <typename R, typename... A, typename F>
class funcWrap<R(A...), F> {
private:
F fun;
public:
funcWrap(F fun): fun(fun) {}
std::string operator()(std::stack<std::string>& args) {
std::tuple<typename std::decay<A>::type...> t{ makeArg<A>(args)... };
std::ostringstream out;
out << util::apply(this->fun, t);
return out.str();
}
};
template <typename R, typename... A, typename S, typename... B>
class funcWrap<R(A...), R (S::*)(B...)> {
private:
R (S::*mem)(B...);
public:
funcWrap(R (S::*mem)(B...)): mem(mem) {}
std::string operator()(std::stack<std::string>& args) {
std::tuple<typename std::decay<A>::type...> t{ makeArg<A>(args)... };
std::ostringstream out;
out << util::apply([=](S& s, B... b){ return (s.*(this->mem))(b...); }, t);
return out.str();
}
};
// ----------------------------------------------------------------------------
template <typename R, typename... A>
funcWrap<R(A...), R(*)(A...)>
wrap(R(*fun)(A...)) { // deal with functions
return funcWrap<R(A...), R(*)(A...)>(fun);
}
template <typename Signature, typename F>
funcWrap<Signature, F>
wrap(F&& f) { // deal with function objects
return funcWrap<Signature, F>(std::forward<F>(f));
}
template <typename R, typename S, typename... A>
funcWrap<R(S&, A...), R (S::*)(A...)>
wrap(R(S::*mem)(A...)) {
return funcWrap<R(S&, A...), R (S::*)(A...)>(mem);
}
float add(float f0, float f1) { return f0 + f1; }
struct adder {
float value;
explicit adder(float value): value(value) {}
float operator()(float f0, float f1) {
return value + f0 + f1;
}
};
struct foo {
float value;
foo(): value() {}
explicit foo(float value): value(value) {}
foo mem(foo f) { return foo(value + f.value); }
};
std::istream& operator>> (std::istream& in, foo& f) {
return in >> f.value;
}
std::ostream& operator<< (std::ostream& out, foo const& f) {
return out << f.value;
}
int main() {
std::stack<std::string> args;
auto wfun = wrap(&add);
args.push("17.5");
args.push("42.25");
std::cout << "wfun result=" << wfun(args) << "\n";
auto wobj = wrap<float(float, float)>(adder(3.125));
args.push("17.5");
args.push("42.25");
std::cout << "wobj result=" << wobj(args) << "\n";
auto wmem = wrap(&foo::mem);
args.push("17.5");
args.push("42.25");
std::cout << "wmem result=" << wmem(args) << "\n";
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
// ----------------------------------------------------------------------------
模板
typename std::decage::type makeArg(std::stack&args){
typename std::decation::type rc;
if(args.empty()| |!(std::istringstream(args.top())>>rc)){
抛出std::runtime_错误(“无法从“+(args.empty()?”:args.top())+”)创建参数;
}
args.pop();
返回rc;
}
// ----------------------------------------------------------------------------
命名空间util
{
模板
结构整数序列{
};
模板
使用索引\序列=整数\序列;
模板
结构整型序列器{
使用type=typename integer\u sequencer::type;
};
模板
结构整型序列器{
使用类型=整数\u序列;
};
模板
使用make_integer_sequence=typename integer_sequencer::type;
模板
使用make_index_sequence=make_integer_sequence;
模板
自动应用(F&&fun,T&&tuple,索引序列)->decltype(fun(std::get(tuple)…){
返回乐趣(std::get(tuple)…);
}
模板
自动应用(F&F、T&T)
->decltype(应用辅助(std::forward(f)、std::forward(t)、make_index_sequence()){
返回apply_aux(std::forward(f)、std::forward(t)、make_index_sequence());
}
}
// ----------------------------------------------------------------------------
模板类;
模板
类函数包{
私人:
F乐趣;
公众:
funcWrap(F fun):fun(fun){}
std::string运算符()(std::stack和args){
std::元组t{makeArg(args)…};
std::ostringstream out;
出去玩,t);
return out.str();
}
};
模板
类函数包{
私人:
R(S::*成员)(B.);
公众:
funcWrap(R(S::*mem)(B…):mem(mem){}
std::string运算符()(std::stack和args){
std::元组t{makeArg(args)…};
std::ostringstream out;
out mem)(b…;},t);
return out.str();
}
};
// ----------------------------------------------------------------------------
模板
复卷
换行符(R(*fun)(A…){//处理函数
返回(乐趣);
}
模板
复卷
wrap(F&&F){//处理函数对象
返回函数(std::forward(f));
}
模板
复卷
包装(R(S::*mem)(A…){
返回函数包(mem);
}
浮点加法(浮点f0,浮点f1){返回f0+f1;}
结构加法器{
浮动值;
显式加法器(浮点值):值(值){}
浮点运算符()(浮点f0,浮点f1){
返回值+f0+f1;
}
};
结构foo{
浮动值;
foo():value(){}
显式foo(浮点值):值(值){}
foo mem(foo f){return foo(value+f.value);}
};
std::istream&operator>>(std::istream&in,foo&f){
返回>>f.value;
}
std::ostream&operator尽管修复了一些拼写错误(例如,加法器的operator()(float,float)),但还不能编译它(GCC4.8,带有-c++1y)。然而,你的方法对我来说非常有意义。只是细节,就像模板一样,对我的大脑产生了有趣的影响。@user3849418:是的,有一些拼写错误:我在手机上拼凑了代码。我添加了一个完整的实现
float add(float, float);
struct adder { float operator()(float, float); };
struct foo { foo mem(foo); };
int main() {
auto wfun = wrap(&add);
auto wobj = wrap<float(float, float)>(adder());
auto wmem = wrap(&foo::mem);
}
#include <iostream>
#include <sstream>
#include <stack>
#include <string>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <utility>
#include <cstddef>
// ----------------------------------------------------------------------------
template <typename T>
typename std::decay<T>::type makeArg(std::stack<std::string>& args) {
typename std::decay<T>::type rc;
if (args.empty() || !(std::istringstream(args.top()) >> rc)) {
throw std::runtime_error("can't create argument from '" + (args.empty()? "<empty>": args.top()) + "'");
}
args.pop();
return rc;
}
// ----------------------------------------------------------------------------
namespace util
{
template<typename T, T...>
struct integer_sequence {
};
template<std::size_t... I>
using index_sequence = integer_sequence<std::size_t, I...>;
template <typename T, std::size_t N, T... I>
struct integer_sequencer {
using type = typename integer_sequencer<T, N - 1, N - 1, I...>::type;
};
template <typename T, T... I>
struct integer_sequencer<T, 0, I...> {
using type = integer_sequence<T, I...>;
};
template<typename T, T N>
using make_integer_sequence = typename integer_sequencer<T, N>::type;
template<std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
template <typename F, typename T, std::size_t... I>
auto apply_aux(F&& fun, T&& tuple, index_sequence<I...>) -> decltype(fun(std::get<I>(tuple)...)) {
return fun(std::get<I>(tuple)...);
}
template <typename F, typename T>
auto apply(F&& f, T&& t)
-> decltype(apply_aux(std::forward<F>(f), std::forward<T>(t), make_index_sequence<std::tuple_size<typename std::decay<T>::type>::value>())) {
return apply_aux(std::forward<F>(f), std::forward<T>(t), make_index_sequence<std::tuple_size<typename std::decay<T>::type>::value>());
}
}
// ----------------------------------------------------------------------------
template <typename S, typename F> class funcWrap;
template <typename R, typename... A, typename F>
class funcWrap<R(A...), F> {
private:
F fun;
public:
funcWrap(F fun): fun(fun) {}
std::string operator()(std::stack<std::string>& args) {
std::tuple<typename std::decay<A>::type...> t{ makeArg<A>(args)... };
std::ostringstream out;
out << util::apply(this->fun, t);
return out.str();
}
};
template <typename R, typename... A, typename S, typename... B>
class funcWrap<R(A...), R (S::*)(B...)> {
private:
R (S::*mem)(B...);
public:
funcWrap(R (S::*mem)(B...)): mem(mem) {}
std::string operator()(std::stack<std::string>& args) {
std::tuple<typename std::decay<A>::type...> t{ makeArg<A>(args)... };
std::ostringstream out;
out << util::apply([=](S& s, B... b){ return (s.*(this->mem))(b...); }, t);
return out.str();
}
};
// ----------------------------------------------------------------------------
template <typename R, typename... A>
funcWrap<R(A...), R(*)(A...)>
wrap(R(*fun)(A...)) { // deal with functions
return funcWrap<R(A...), R(*)(A...)>(fun);
}
template <typename Signature, typename F>
funcWrap<Signature, F>
wrap(F&& f) { // deal with function objects
return funcWrap<Signature, F>(std::forward<F>(f));
}
template <typename R, typename S, typename... A>
funcWrap<R(S&, A...), R (S::*)(A...)>
wrap(R(S::*mem)(A...)) {
return funcWrap<R(S&, A...), R (S::*)(A...)>(mem);
}
float add(float f0, float f1) { return f0 + f1; }
struct adder {
float value;
explicit adder(float value): value(value) {}
float operator()(float f0, float f1) {
return value + f0 + f1;
}
};
struct foo {
float value;
foo(): value() {}
explicit foo(float value): value(value) {}
foo mem(foo f) { return foo(value + f.value); }
};
std::istream& operator>> (std::istream& in, foo& f) {
return in >> f.value;
}
std::ostream& operator<< (std::ostream& out, foo const& f) {
return out << f.value;
}
int main() {
std::stack<std::string> args;
auto wfun = wrap(&add);
args.push("17.5");
args.push("42.25");
std::cout << "wfun result=" << wfun(args) << "\n";
auto wobj = wrap<float(float, float)>(adder(3.125));
args.push("17.5");
args.push("42.25");
std::cout << "wobj result=" << wobj(args) << "\n";
auto wmem = wrap(&foo::mem);
args.push("17.5");
args.push("42.25");
std::cout << "wmem result=" << wmem(args) << "\n";
}