用于函数对象更改参数和返回值类型的包装器 我想编写C++类(让类型名称为适配器),它接受构造函数中的函数指针或函数对象(特别是lambda函数),并通过内部值(如STD::EngultExpPL函数)来存储它。在构建类之后,它也表示函数对象,并充当内部函数对象的包装器。但有以下条件: 包装类(适配器)的返回类型始终是预定义的(让它成为ReturnType) 但内部函子可能并没有返回值——在本例中,某些DefaultValue被替换 包装器类始终接收一些ArgType作为运算符()的参数 但内部函数也可以接收ArgType作为参数,或者可能根本不接受参数——在后一种情况下,只应在不带参数的情况下调用它
第一个问题——这在C++11中是可能的,第二个问题是我如何做到这一点?我不知道从哪里开始 我需要推断(在模板中)函数对象的返回值?第一个陷阱是std::result_不支持函数指针。我不知道如何为函数对象推断参数类型(可能为空、无参数或ArgType)(我知道如何通过模板结构为函数指针推断参数类型,但如何为函数对象推断参数类型?) 我需要这样的东西:用于函数对象更改参数和返回值类型的包装器 我想编写C++类(让类型名称为适配器),它接受构造函数中的函数指针或函数对象(特别是lambda函数),并通过内部值(如STD::EngultExpPL函数)来存储它。在构建类之后,它也表示函数对象,并充当内部函数对象的包装器。但有以下条件: 包装类(适配器)的返回类型始终是预定义的(让它成为ReturnType) 但内部函子可能并没有返回值——在本例中,某些DefaultValue被替换 包装器类始终接收一些ArgType作为运算符()的参数 但内部函数也可以接收ArgType作为参数,或者可能根本不接受参数——在后一种情况下,只应在不带参数的情况下调用它,c++,c++11,templates,C++,C++11,Templates,第一个问题——这在C++11中是可能的,第二个问题是我如何做到这一点?我不知道从哪里开始 我需要推断(在模板中)函数对象的返回值?第一个陷阱是std::result_不支持函数指针。我不知道如何为函数对象推断参数类型(可能为空、无参数或ArgType)(我知道如何通过模板结构为函数指针推断参数类型,但如何为函数对象推断参数类型?) 我需要这样的东西: template <typename Functor?> class Adapter { private: std::func
template <typename Functor?> class Adapter
{
private:
std::function<Void_or_ReturnType (Void_or_ArgType)> f;
public:
template <typename Functor?> Adapter(const Functor& f) { ??? }
ReturnType operator()(ArgType arg)
{
// one of the following four variants:
return f(arg);
f(arg); return DefaultValue;
return f();
f(); return DefaultValue;
}
};
模板类适配器
{
私人:
std::函数f;
公众:
模板适配器(常量函子&f){???}
ReturnType运算符()(ArgType arg)
{
//以下四种变体之一:
返回f(arg);
f(arg);返回DefaultValue;
返回f();
f();返回DefaultValue;
}
};
可能我需要推导模板中的Void_或_ReturnType和Void_或_ArgType类型,并为运算符()编写不同的模板专门化,这四种情况各有不同。但我究竟如何才能做到这一点呢?我花了几个小时在这方面,并找到了一些解决方案: 不确定,这是否是一个好的解决方案。可能有人建议我,我怎样才能最小化这个代码 我在这里复制源代码以防万一(我在coliru.stacked-crooked.com上更新了源代码,这里是旧版本,请参阅上面的链接):
#包括
#包括
//函子
模板结构IsArgs{typedef typename IsArgs::type;};
模板结构IsResult{typedef typename IsResult::type;};
//函数指针
模板结构IsArgs{typedef Yes type;};
模板结构IsArgs{typedef No type;};
模板结构IsResult{typedef Yes type;};
模板结构IsResult{typedef No type;};
//对于函数引用
模板结构IsArgs{typedef Yes type;};
模板结构IsArgs{typedef No type;};
模板结构IsResult{typedef Yes type;};
模板结构IsResult{typedef No type;};
//用于成员指针(lambdas、函子)
模板结构IsArgs{typedef Yes type;};
模板结构IsArgs{typedef No type;};
模板结构IsResult{typedef Yes type;};
模板结构IsResult{typedef No type;};
模板类适配器
{
结构Noargs{
std::函数func;
模板Noargs(常数F&F):func(F){}
Retval运算符()(Args…{return func();}
};
结构Noreturn{
std::函数func;
模板Noreturn(常数F&F):func(F){}
Retval运算符()(Args…Args){return func(Args…,默认;}
};
结构NORETAGS{
std::函数func;
模板Noretargs(常数F&F):func(F){}
Retval运算符()(Args…{return func(),默认;}
};
std::函数func;
公众:
模板适配器(常量函子&f)
:func(typename IsArgs::type(f)){}
Retval运算符()(Args…Args)常量{return func(Args…;}
};
void dead_silent_f(){put(“dead/silent”);}
void silent_f(const char*arg){printf(“silent%s\n”,arg);}
const char*dead_f(){puts(“dead”);返回“dead”;}
常量字符*normal\u f(常量字符*arg){printf(“normal%s\n”,arg);返回“normal”}
常量字符默认值[]=“默认值”;
int main(int argc,char*argv[])
{
类型定义适配器A;
{
puts(“函数引用”);
A ds(聋哑);printf(“->%s\n”,ds(“ds”);
A s(无声);printf(“->%s\n”,s(“s”));
A d(聋子);printf(“->%s\n”,d(“d”);
A n(正常);printf(“->%s\n”,n(“n”);
认沽权(“”);
}
{
puts(“函数指针”);
一个ds(&dead\u silent\u f);printf(“->%s\n”,ds(“ds”));
A s(&silent);printf(“->%s\n”,s(“s”));
A d(&d);printf(“->%s\n”,d(“d”);
A n(&normal);printf(“->%s\n”,n(“n”));
认沽权(“”);
}
{
看跌期权(“函子”);
一个ds([=]{printf(“聋哑/无声的%d\n”,argc);});printf(“->%s\n”,ds(“ds”);
A s([=](常量字符*A){printf(“静默(%s)%d\n”,A,argc);});printf(“->%s\n”,s(“s”));
A d([=]{printf(“聋子%d\n”,argc);返回“聋子”});printf(->%s\n,d(“d”);
A n([=](常量字符*A){printf(“正常(%s)%d\n”,A,argc);返回“正常”});printf(->%s\n),n(“n”);
}
返回0;
}
嗯。。。你问的并不是那么简单
首先:我认为将默认返回值作为模板参数不是一个好主意:适用于整数类型,但例如,不适用于浮点类型。您可以绕过这个问题,但我建议将默认值作为值传递到构造函数中
第二:我建议使用以下代码来检测F
id类型的可调用对象是否可以使用给定的类型列表进行调用
template <typename ...>
constexpr std::false_type isInvocableWithHelper (long);
template <typename F, typename ... Args>
constexpr auto isInvocableWithHelper (int)
-> decltype( std::declval<F>()
(std::forward<Args>(std::declval<Args>())...),
std::true_type{} );
template <typename F, typename ... Args>
using isInvocableWith = decltype(isInvocableWithHelper<F, Args...>(0));
其中,只有当F
对象可通过Args…
对象和
template <typename F>
Adapter (F const & f, RetT defVal = RetT{})
: Adapter{f, defVal, isInvocableWith<F, Args...>{},
isInvocableWith<F>{}}
{ }
template <typename F>
Adapter (F const & f, RetT const & defVal, std::true_type const &,
std::false_type const &)
: Adapter{f, defVal, std::true_type{}, std::false_type{},
std::is_same<void,
decltype(f(std::forward<Args>(std::declval<Args>())...))>{}}
{ }
template <typename F>
Adapter (F const & f, RetT const & defVal, std::false_type const &,
std::true_type const &)
: Adapter{f, defVal, std::false_type{}, std::true_type{},
std::is_same<void, decltype(f())>{}}
{ }
template <typename F>
Adapter (F const & f, RetT const & defVal, std::true_type const &,
std::false_type const &, std::true_type const &)
: defV{defVal}
{
func = [&, this](Args && ... as)
{ f(std::forward<Args>(as)...); return defV; };
std::cout << "--- case 1 (full, void)" << std::endl;
}
template <typename F>
Adapter (F const & f, RetT const &, std::true_type const &,
std::false_type const &, std::false_type const &)
{
func = [&](Args && ... as)
{ return f(std::forward<Args>(as)...); };
std::cout << "--- case 2 (full, RetT)" << std::endl;
}
template <typename F>
Adapter (F const & f, RetT const & defVal, std::false_type const &,
std::true_type const &, std::true_type const &)
: defV{defVal}
{
func = [&, this](Args && ...)
{ f(); return defV; };
std::cout << "--- case 3 (noArgs, void)" << std::endl;
}
template <typename F>
Adapter (F const & f, RetT const &, std::false_type const &,
std::true_type const &, std::false_type const &)
{
func = [&](Args && ...)
{ return f(); };
std::cout << "--- case 4 (noArgs, RetT)" << std::endl;
}
#include <cstdio>
#include <iostream>
#include <functional>
template <typename ...>
constexpr std::false_type isInvocableWithHelper (long);
template <typename F, typename ... Args>
constexpr auto isInvocableWithHelper (int)
-> decltype( std::declval<F>()
(std::forward<Args>(std::declval<Args>())...),
std::true_type{} );
template <typename F, typename ... Args>
using isInvocableWith = decltype(isInvocableWithHelper<F, Args...>(0));
template <typename RetT, typename ... Args>
class Adapter
{
private:
std::function<RetT(Args ...)> func;
RetT defV { RetT{} };
template <typename F>
Adapter (F const & f, RetT const & defVal, std::true_type const &,
std::false_type const &, std::true_type const &)
: defV{defVal}
{
func = [&, this](Args && ... as)
{ f(std::forward<Args>(as)...); return defV; };
std::cout << "--- case 1 (full, void)" << std::endl;
}
template <typename F>
Adapter (F const & f, RetT const &, std::true_type const &,
std::false_type const &, std::false_type const &)
{
func = [&](Args && ... as)
{ return f(std::forward<Args>(as)...); };
std::cout << "--- case 2 (full, RetT)" << std::endl;
}
template <typename F>
Adapter (F const & f, RetT const & defVal, std::false_type const &,
std::true_type const &, std::true_type const &)
: defV{defVal}
{
func = [&, this](Args && ...)
{ f(); return defV; };
std::cout << "--- case 3 (noArgs, void)" << std::endl;
}
template <typename F>
Adapter (F const & f, RetT const &, std::false_type const &,
std::true_type const &, std::false_type const &)
{
func = [&](Args && ...)
{ return f(); };
std::cout << "--- case 4 (noArgs, RetT)" << std::endl;
}
template <typename F>
Adapter (F const & f, RetT const & defVal, std::true_type const &,
std::false_type const &)
: Adapter{f, defVal, std::true_type{}, std::false_type{},
std::is_same<void,
decltype(f(std::forward<Args>(std::declval<Args>())...))>{}}
{ }
template <typename F>
Adapter (F const & f, RetT const & defVal, std::false_type const &,
std::true_type const &)
: Adapter{f, defVal, std::false_type{}, std::true_type{},
std::is_same<void, decltype(f())>{}}
{ }
public:
template <typename F>
Adapter (F const & f, RetT defVal = RetT{})
: Adapter{f, defVal, isInvocableWith<F, Args...>{},
isInvocableWith<F>{}}
{ }
template <typename ... As>
RetT operator() (As && ... as) const
{ return func(std::forward<As>(as)...); }
};
void deaf_silent_f ()
{ puts("deaf/silent"); }
void silent_f (char const * arg)
{ printf("silent %s\n", arg); }
char const * deaf_f ()
{ puts("deaf"); return "deaf"; }
char const * normal_f (char const * arg)
{ printf("normal %s\n", arg); return "normal"; }
int main ()
{
typedef Adapter<char const *, char const *> A;
{
puts("function refs");
A ds(deaf_silent_f, "Def1"); printf("-> %s\n", ds("ds"));
A s(silent_f, "Def2"); printf("-> %s\n", s("s"));
A d(deaf_f); printf("-> %s\n", d("d"));
A n(normal_f); printf("-> %s\n", n("n"));
puts("");
}
{
puts("function pointers");
A ds(&deaf_silent_f, "Def3"); printf("-> %s\n", ds("ds"));
A s(&silent_f, "Def4"); printf("-> %s\n", s("s"));
A d(&deaf_f); printf("-> %s\n", d("d"));
A n(&normal_f); printf("-> %s\n", n("n"));
puts("");
}
{
puts("functors");
A ds([=]{ printf("deaf/silent %d\n", 42); }, "Def5");
printf("-> %s\n", ds("ds"));
A s([=](char const * a){ printf("silent(%s) %d\n", a, 42); }, "Def6");
printf("-> %s\n", s("s"));
A d([=]{ printf("deaf %d\n", 42); return "deaf"; });
printf("-> %s\n", d("d"));
A n([=](char const * a){ printf("normal(%s) %d\n", a, 42);
return "normal";});
printf("-> %s\n", n("n"));
}
}