存储具有不同类型的函数指针C ++ boost :: bind [英] Storing function pointers with different types c++ boost::bind

查看:125
本文介绍了存储具有不同类型的函数指针C ++ boost :: bind的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我今天挖了很多东西,空了出来。有什么方法可以存储从boost :: bind与不同类型返回的函子吗?我找到了一个使用boost :: variants的示例,但不确定是否需要这样做。 (为简单起见,简化了Foo和Bar)

I have dug around quite a bit today and have come up empty. Is there any way to store a functor that is returned from a boost::bind with different types? I found an example that used boost::variants but not sure that this is needed. (Foo and Bar have been simplified for simplicity sake)

#include <boost/bind.hpp>
#include <boost/variant.hpp>
#include <boost/function.hpp>

#include <map>
#include <iostream>

template <typename FooType>
struct Foo {
    const FooType tmp_value;

    Foo(const FooType& tmp_) :
    tmp_value(tmp_)
    {
    }

    template<typename Object>
    void operator()(Object& operand)
    {
        std::cout << operand << std::endl;
        operand += tmp_value;
    }
};

template <typename BarType>
struct Bar {
    const BarType tmp_value;

    Bar(const BarType& tmp_) :
    tmp_value(tmp_)
    {
    }

    template<typename Object>
    void operator()(Object& operand)
    {
        std::cout << operand << std::endl;
        operand -= tmp_value;
    }
};

typedef boost::variant<
    boost::function<void(int32_t)>,
    boost::function<void(int64_t)>,
    boost::function<void(double)>,
    boost::function<void(float)>
> my_functions;

typedef std::map<std::string, my_functions> test_map;

enum test_t {
    FOO,
    BAR
};

test_map createFunMap() {
  test_map result;

    for(int i = 0; i < 2; i++) {
        switch(i) {
            case test_t::FOO: {
                std::cout << "In FOO" << std::endl;
                Foo<double> p(1.0);
                result.insert(std::pair<std::string, 
                                        boost::function<void(double)>>
                                        ("foo", boost::bind<void>(p, _1)));
              break;
            }
            case test_t::BAR: {
                std::cout << "In BAR" << std::endl;
                Bar<int32_t> p(1.0);
                result.insert(std::pair<std::string, 
                                        boost::function<void(int32_t)>>
                                        ("bar", boost::bind<void>(p, _1)));
              break;
            }
            default:
              std::cout << "just a default" << std::endl;
              break;
        }
    }

  return result;
}

int main() {
    test_map myMap;
    double t = 5.0;

    myMap = createFunMap();

    std::cout << t << std::endl;
    myMap["foo"](t);
    std::cout << t << std::endl;

    return 0;
}

编译器输出:

g++ -Wall --std=c++0x -I. test_ptrs.cc -o test_ptrs
test_ptrs.cc:93:2: error: type 'mapped_type' (aka 'boost::variant<boost::function<void (int)>,         boost::function<void (long long)>, boost::function<void (double)>, boost::function<void (float)>,
  boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_,
  boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_,
  boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>') does not provide a call operator
    myMap["foo"](t);
    ^~~~~~~~~~~~
1 error generated.

谢谢。

推荐答案

您有多态函子(Foo和Bar)。

You have polymorphic functors (Foo and Bar).

您要针对某些操作数类型键入擦除它们。我建议为此定义一个类型擦除的仿函数类型:

You want to type erase them for a certain set of operand types. I suggest defining a type-erased functor type for the purpose:

struct ErasedFunctor
{
    template<typename F> ErasedFunctor(F&& f) 
        : pimpl(new impl_<F>(std::forward<F>(f))) {}

    template <typename T>
    void operator()(T& oper) const {
        assert(pimpl);
        pimpl->call(oper);
    }

  private:
    typedef boost::variant<int32_t&, int64_t&, double&, float&> Operand;

    struct base_ { virtual void call(Operand oper) const = 0; };
    // struct impl_ : base_ ... 

    std::shared_ptr<base_> pimpl;
};

现在,您可以直接在地图中直接存储功能对象:

Now you can simply store the function objects directly in the map:

typedef std::map<std::string, ErasedFunctor> test_map;

test_map createFunMap() {
    return test_map { 
        { "foo", Foo<double>(1.0) },
        { "bar", Bar<int32_t>(1)  },
    };
}

让我们使用 at( foo)而不是 [ foo] ,以避免必须使 ErasedFunctor 默认可构造:

Let's use at("foo") instead of ["foo"] to avoid having to make ErasedFunctor default-constructible:

int main() {
    test_map myMap = createFunMap();
    double t = 5.0;

    std::cout << t << std::endl;
    myMap.at("foo")(t);
    std::cout << t << std::endl;
    myMap.at("bar")(t);
    std::cout << t << std::endl;
}

打印

5
void ErasedFunctor::apply::operator()(const F&, T&) const [with F = Foo<double>; T = double](5)
5
6
void ErasedFunctor::apply::operator()(const F&, T&) const [with F = Bar<int>; T = double](6)
6
5

查看它 在Coliru上直播

See it Live On Coliru

有关更多背景信息,请参见:

For more background see:

#include <boost/bind.hpp>
#include <boost/variant.hpp>
#include <iostream>

template <typename FooType> struct Foo {
    const FooType tmp_value;

    Foo(const FooType &tmp_) : tmp_value(tmp_) {}

    template <typename Object> void operator()(Object &operand) const {
        std::cout << operand << std::endl;
        operand += tmp_value;
    }
};

template <typename BarType> struct Bar {
    const BarType tmp_value;

    Bar(const BarType &tmp_) : tmp_value(tmp_) {}

    template <typename Object> void operator()(Object &operand) const {
        std::cout << operand << std::endl;
        operand -= tmp_value;
    }
};

struct ErasedFunctor
{
    template<typename F> ErasedFunctor(F&& f) 
        : pimpl(new impl_<F>(std::forward<F>(f))) {}

    template <typename T>
    void operator()(T& oper) const {
        assert(pimpl);
        pimpl->call(oper);
    }

  private:
    typedef boost::variant<int32_t&, int64_t&, double&, float&> Operand;

    struct base_ { virtual void call(Operand oper) const = 0; };

    struct apply : boost::static_visitor<void> {
        template <typename F, typename T> void operator()(F const& f, T& v) const {
            std::cout << __PRETTY_FUNCTION__ << "(" << v << ")\n";
            f(v);
        }
    };

    template <typename F> struct impl_ : base_ {
        F f_;
        impl_(F&& f) : f_(std::forward<F>(f)) { }
        virtual void call(Operand oper) const override {
            boost::apply_visitor(boost::bind(apply(), boost::cref(f_), _1), oper);
        }
    };

    std::shared_ptr<base_> pimpl;
};

#include <map>
typedef std::map<std::string, ErasedFunctor> test_map;

test_map createFunMap() {
    return test_map { 
        { "foo", Foo<double>(1.0) },
        { "bar", Bar<int32_t>(1)  },
    };
}

int main() {
    test_map myMap = createFunMap();
    double t = 5.0;

    std::cout << t << std::endl;
    myMap.at("foo")(t);
    std::cout << t << std::endl;
    myMap.at("bar")(t);
    std::cout << t << std::endl;
}

这篇关于存储具有不同类型的函数指针C ++ boost :: bind的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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