如何重载一个运算符在C ++ 0x中的函数组合? [英] How to overload an operator for composition of functionals in C++0x?

查看:91
本文介绍了如何重载一个运算符在C ++ 0x中的函数组合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法重载,比如>> 运算符的函数组合?运营商应该在lambdas上以及 std :: function



无缝工作要求:




  • 解决方案不应包含嵌套绑定调用,

  • 左操作数可以是具有任意数量参数的函数类型,并且
  • 应该创建不超过一个函数对象实例。

>

以下是一个快速而肮脏的例子,说明了所需的行为:

 #包括< iostream> 
#include< functional>

使用namespace std;

//一个快速而脏的函数组合的例子。
//注意,不是'std :: function',这个运算符应该接受
//任何函数/可调用类型(就像'bind'一样)。
模板< typename R1,typename R2,typename ... ArgTypes1>
函数< R2(ArgTypes1 ...)>运算符>> (
const函数< R1(ArgTypes1 ...)& f1,
const function< R2(R1)& f2){
return [=](ArgTypes1。 .. args){return f2(f1(args ...)); };


int main(int argc,char ** args){
auto l1 = [](int i,int j){return i + j;};
auto l2 = [](int i){return i * i;};

函数< int(int,int)> f1 = l1;
函数< int(int)> f2 = l2;

cout<< 功能组合:<< (f1>> f2)(3,5)<< ENDL;

//以下是需要的,但它不会按原样编译:
cout<< 功能组合:<< (l 1> l 2)(3,5) ENDL;

返回0;


解决方案

(l1>> l2)无法工作。



它们是由编译器生成的函数对象,不包含该运算符,所以除非你打算修改编译器是不符合的,这就是它总是如此。 :)

然而,您可以引入一个关键字(实用程序类),这可以说是一件好事,但它很重要:

  // https://ideone.com/MS2E3 

#include< iostream>
#include< functional>

namespace detail
{
template< typename R,typename ... Args>
class composed_function;

//实用工具
模板< typename ... Args>
struct variadic_typedef;

模板< typename Func>
struct callable_type_info:
callable_type_info< decltype(& Func :: operator())>
{};

模板< typename Func>
struct callable_type_info< Func *> :
callable_type_info< Func>
{};

模板< typename DeducedR,typename ... DeducedArgs>
struct callable_type_info< DeducedR(DeducedArgs ...)>
{
typedef DeducedR return_type;
typedef variadic_typedef< DeducedArgs ...> args_type;
};

模板< typename O,typename DeducedR,typename ... DeducedArgs>
struct callable_type_info< DeducedR(O :: *)(DeducedArgs ...)const>
{
typedef DeducedR return_type;
typedef variadic_typedef< DeducedArgs ...> args_type;
};

模板< typename DeducedR,typename ... DeducedArgs>
struct callable_type_info< std :: function< DeducedR(DeducedArgs ...)>>
{
typedef DeducedR return_type;
typedef variadic_typedef< DeducedArgs ...> args_type;
};

模板< typename Func>
struct return_type
{
typedef typename callable_type_info< Func> :: return_type type;
};

模板< typename Func>
struct args_type
{
typedef typename callable_type_info< Func> :: args_type type;
};

模板< typename FuncR,typename ... FuncArgs>
struct composed_function_type
{
typedef composed_function< FuncR,FuncArgs ...>类型;
};

模板< typename FuncR,typename ... FuncArgs>
struct composed_function_type< FuncR,variadic_typedef< FuncArgs ...>> :
composed_function_type< FuncR,FuncArgs ...>
{};

模板< typename R,typename ... Args>
类合成函数

public
合成函数(std :: function< R(Args ...)> func):
mFunction(std :: move (func))
{}

模板< typename ... CallArgs>
R operator()(CallArgs&& ... args)
{
return mFunction(std :: forward< CallArgs>(args)...);
}

模板< typename Func>
typename composed_function_type<
typename return_type< Func> :: type,Args ...> :: type
operator>>(Func func)/ *&& * / //只有rvalues(现在不支持)
{
std :: function< R(Args ...)> thisFunc = std :: move(mFunction);

返回类型名称compos_function_type<
typename return_type< Func> :: type,Args ...> :: type(
[=](Args ... args)
{
return func(thisFunc (args ...));
});
}

private:
std :: function< R(Args ...)> mFunction;
};
}

模板< typename Func>
typename detail :: composed_function_type<
typename detail :: return_type< Func> :: type,
typename detail :: args_type< Func> :: type> :: type
compose(Func func)
{
return typename detail :: composed_function_type<
typename detail :: return_type< Func> :: type,
typename detail :: args_type< Func> :: type> :: type(func);
}

int main()
{
using namespace std;

auto l1 = [](int i,int j){return i + j;};
auto l2 = [](int i){return i * i;};

std:function< int(int,int)> f1 = l1;
函数< int(int)> f2 = l2;

cout<< 功能组合:<< (compose(f1)>> f2)(3,5)<< ENDL;
cout<< 功能组合:<< (构成(l 1)> l 2)(3,5)< ENDL;
cout<< 功能组合:<< (compose(f1)>> 12)(3,5)<< ENDL;
cout<< 功能组合:<< (组成(l1)> f2)(3,5) ENDL;

返回0;

这是相当多的代码!不幸的是,我不明白它是如何减少的。



你可以选择另一条路线,只要在你的方案中使用lambdas,你只需要明确地使它们成为 std :: function<> s,但它不那么统一。上面的一些机制可以用来为lambda函数制作一些 to_function()函数为 std :: function<> code> s。


Is there a way to overload, say the >> operator for function composition? The operator should work seamlessly on lambdas as well as std::function?

Requirements:

  • The solution should not include nested bind calls,
  • the left operand can be of a functional type with an arbitrary number of parameters, and
  • no more than one function object instance should be created.

Here is a quick and dirty example that illustrates the desired behaviour:

#include <iostream>
#include <functional>

using namespace std;

// An example of a quick and dirty function composition.
// Note that instead of 'std::function' this operator should accept
// any functional/callable type (just like 'bind').
template<typename R1, typename R2, typename... ArgTypes1>
function<R2(ArgTypes1...)> operator >> (
                const function<R1(ArgTypes1...)>& f1,
                const function<R2(R1)>& f2) {
    return [=](ArgTypes1... args){ return f2(f1(args...)); };
}

int main(int argc, char **args) {
    auto l1 = [](int i, int j) {return i + j;};
    auto l2 = [](int i) {return i * i;};

    function<int(int, int)> f1 = l1;
    function<int(int)> f2 = l2;

    cout << "Function composition: " << (f1 >> f2)(3, 5) << endl;

    // The following is desired, but it doesn't compile as it is:
    cout << "Function composition: " << (l1 >> l2)(3, 5) << endl;

    return 0;
}

解决方案

(l1 >> l2) can never work.

They are function objects made by the compiler and don't include that operator, so unless you plan on modifying the compiler to be non-conforming that's how it's always going to be. :)

You can, however, introduce a "keyword" (utility class) which is arguably a good thing, but it's hefty:

// https://ideone.com/MS2E3

#include <iostream>
#include <functional>

namespace detail
{
    template <typename R, typename... Args>
    class composed_function;

    // utility stuff
    template <typename... Args>
    struct variadic_typedef;

    template <typename Func>
    struct callable_type_info :
        callable_type_info<decltype(&Func::operator())>
    {};

    template <typename Func>
    struct callable_type_info<Func*> :
        callable_type_info<Func>
    {};

    template <typename DeducedR, typename... DeducedArgs>
    struct callable_type_info<DeducedR(DeducedArgs...)>
    {
        typedef DeducedR return_type;
        typedef variadic_typedef<DeducedArgs...> args_type;
    };

    template <typename O, typename DeducedR, typename... DeducedArgs>
    struct callable_type_info<DeducedR (O::*)(DeducedArgs...) const>
    {
        typedef DeducedR return_type;
        typedef variadic_typedef<DeducedArgs...> args_type;
    };

    template <typename DeducedR, typename... DeducedArgs>
    struct callable_type_info<std::function<DeducedR(DeducedArgs...)>>
    {
        typedef DeducedR return_type;
        typedef variadic_typedef<DeducedArgs...> args_type;
    };

    template <typename Func>
    struct return_type
    {
        typedef typename callable_type_info<Func>::return_type type;
    };

    template <typename Func>
    struct args_type
    {
        typedef typename callable_type_info<Func>::args_type type;
    };

    template <typename FuncR, typename... FuncArgs>
    struct composed_function_type
    {
        typedef composed_function<FuncR, FuncArgs...> type;
    };

    template <typename FuncR, typename... FuncArgs>
    struct composed_function_type<FuncR, variadic_typedef<FuncArgs...>> :
        composed_function_type<FuncR, FuncArgs...>
    {};

    template <typename R, typename... Args>
    class composed_function
    {
    public:
        composed_function(std::function<R(Args...)> func) :
        mFunction(std::move(func))
        {}

        template <typename... CallArgs>
        R operator()(CallArgs&&... args)
        {
            return mFunction(std::forward<CallArgs>(args)...);
        }

        template <typename Func>
        typename composed_function_type<
                    typename return_type<Func>::type, Args...>::type
             operator>>(Func func) /* && */ // rvalues only (unsupported for now)
        {
            std::function<R(Args...)> thisFunc = std::move(mFunction);

            return typename composed_function_type<
                                typename return_type<Func>::type, Args...>::type(
                                        [=](Args... args)
                                        {
                                            return func(thisFunc(args...));
                                        });
        }

    private:    
        std::function<R(Args...)> mFunction;
    };
}

template <typename Func>
typename detail::composed_function_type<
            typename detail::return_type<Func>::type,
                typename detail::args_type<Func>::type>::type
    compose(Func func)
{
    return typename detail::composed_function_type<
                        typename detail::return_type<Func>::type,
                            typename detail::args_type<Func>::type>::type(func);
}

int main()
{
    using namespace std;

    auto l1 = [](int i, int j) {return i + j;};
    auto l2 = [](int i) {return i * i;};

    std:function<int(int, int)> f1 = l1;
    function<int(int)> f2 = l2;

    cout << "Function composition: " << (compose(f1) >> f2)(3, 5) << endl;
    cout << "Function composition: " << (compose(l1) >> l2)(3, 5) << endl;
    cout << "Function composition: " << (compose(f1) >> l2)(3, 5) << endl;
    cout << "Function composition: " << (compose(l1) >> f2)(3, 5) << endl;

    return 0;

That's a quite a bit of code! Unfortunately I don't see how it can be reduced any.

You can go another route and just make it so to use lambdas in your scheme, you just have to explicitly make them std::function<>s, but it's less uniform. Some of the machinery above could be used to make some sort of to_function() function for making lambda functions into std::function<>s.

这篇关于如何重载一个运算符在C ++ 0x中的函数组合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆