可以使用lambda的类型作为模板参数,例如
template<typename InArg, typename Function>
class selfCompose {
Function f;
public:
selfCompose(Function f): f(f) {}
auto operator() (InArg x) -> decltype(f(f(x))) {
return f(f(x)); }
};
int main() {
auto f = [](int x){return x*x;};
std::cout << selfCompose<int, decltype(f)>(f)(4) // yields (4²)² = 256
<< std::endl;
return 0;
}
然而,f
的这种双重使用是多余的。我们可以省略传递lambda的类型作为模板(将它转换为合适的std::function
(失去多态性 - 但C ++ lambda无论如何都不是参数多态)),但我有一个应用程序,我更喜欢不必将值传递给构造函数(因为我想将我的类的初始化本身用作模板参数,其中需要特定的构造函数签名)。我希望它像
template<class InArg, class Function>
class selfCompose {
Function f;
public:
selfCompose() {} // default constructor for f
auto operator() (InArg x) -> decltype(f(f(x))) {
return f(f(x)); }
};
int main() {
auto f = [](int x){return x*x;};
std::cout << selfCompose<int, decltype(f)>()(4) << std::endl;
return 0;
}
但是这不能编译,因为lambdas有一个删除的默认构造函数。对于捕获 lambdas来说当然是不可避免的,但对于像我这个例子中那样简单的那个,这对我来说没有多大意义:它们不需要引用任何局部变量。
是否有其他方法可以获得此功能,或者我是否必须将lambda旧式定义为命名类?
struct myFun {
auto operator() (int x) -> int {return x*x;}
};
(当然,我想使用的lambda函数不像<{1}}那样简单 ,所以只选择几个标准函数类就不灵活了足够)
答案 0 :(得分:5)
您可以按照make_pair
和make_shared
:
template<typename InArg, typename Function>
selfCompose<InArg, Function> make_selfCompose(Function f)
{
return selfCompose<InArg, decltype(f)>(f);
}
int main() {
auto f = [](int x){return x*x;};
std::cout << make_selfCompose<int>(f)(4)
<< std::endl;
return 0;
}
答案 1 :(得分:1)
如果selfCompose
是多态的,则无需显式传递参数类型或检查存储的仿函数类型。后者意味着它也能够处理多态函子。
template<typename Functor>
struct self_compose_type {
// Omitting encapsulation for brevity
Functor functor;
// It is possible to overload operator() to deal
// with all cv and ref qualifiers combinations
template<typename... T>
auto operator()(T&&... t)
// Don't use std::result_of for the return type
-> decltype( std::declval<Functor&>()(std::declval<T>()...) )
{ return functor(std::forward<T>(t)...); }
};
template<typename Functor>
self_compose_type<Functor>
self_compose(Functor&& functor)
{ return { std::forward<Functor>(functor) }; }
// C++03 style:
template<typename Functor>
self_compose_type<typename std::decay<Functor>::type>
make_self_compose(Functor&& functor)
{ return { std::forward<Functor>(functor) }; }
没有必要制作operator()
变量,如果你愿意,可以让它接受一个参数。
答案 2 :(得分:-2)
本杰明已经为你的案子发布了一个很好的解决方法。你可以使用它。
我的解决方案只是本杰明答案的改进版本,您无需指定lambda参数 type 。所以不要写这个:
make_selfCompose<int>(f)(4); //Benjamin's solution
你可以这样写:
make_selfCompose(f)(4); //improved - absence `int` template argument.
让make_selfCompose
推导出lambda参数类型本身。
对于此解决方案,我们将第一个function_traits
类模板写为:
#include <tuple>
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};
template <typename C, typename R, typename... A>
struct function_traits<R(C::*)(A...) const>
{
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<A...>>::type type;
};
};
然后这是make_selfCompose
的改进版本:
template<typename Fun> //<--- now it has one template parameter
selfCompose<typename function_traits<Fun>::template arg<0>::type, Fun>
make_selfCompose(Fun f)
{
typedef typename function_traits<Fun>::template arg<0>::type InArg; //deduce it
return selfCompose<InArg, decltype(f)>(f);
}
这是测试程序:
int main() {
auto f = [](int x){return x*x;};
std::cout << make_selfCompose(f)(4) //notice the relief here!
<< std::endl;
return 0;
}
希望有所帮助。 : - )