使用带有参数的boost :: function共享指向派生类的指针 [英] Using boost::function with a parameter to shared pointer to derived class

查看:90
本文介绍了使用带有参数的boost :: function共享指向派生类的指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Ubuntu 16.04上将C ++与g ++ 5.4.0结合使用.

Using C++ with g++ 5.4.0 on Ubuntu 16.04.

我有一个类A和一个从类A派生的类B.函数f1将指向类A的共享指针作为参数.函数f2将指向类B的共享指针作为参数,并返回与f1相同的类型.使用boost :: function,另一个函数F将f1之类的函数作为参数.代码如下:

I have a class A, and a class B that derives from class A. Function f1 takes a shared pointer to class A as parameter. Function f2 takes a shared pointer to class B as parameter and return the same type as f1. Using boost::function, another function F takes a function such as f1 as parameter. The code looks like this :

result_t f1 ( const boost::shared_ptr<A> a );
result_t f2 ( const boost::shared_ptr<B> b );
typedef boost::function < result_t (const boost::shared_ptr<A>&) > f1_t;
void F ( const f1_t f );

以f1作为参数调用F可以正常工作.我现在想调用F,但以f2作为参数.我收到以下错误:

Calling F with f1 as argument works fine. I now want to call F but with f2 as argument. I get the following error :

error: invalid initialization of reference of type const boost::shared_ptr<B>& from expression of type const boost::shared_ptr<A>
           return f(BOOST_FUNCTION_ARGS);

执行此错误实际上并不需要F:

There's not really a need for F to get this error, doing :

f1_t f = f2;

给出相同的错误.

推荐答案

函数原型没有协方差.不同的签名就是:不同的类型.

There's no co-variance for function prototypes. Different signatures are simply that: different types.

在这种情况下,您需要使用转换包装器包装函数.

In this case you'd need to wrap the function with a converting wrapper.

让我们创建一些设施定义:

Let's create a few facility definitions:

using result_t = int;
struct A { };
struct B : A { };

typedef boost::shared_ptr<A> APtr;
typedef boost::shared_ptr<B> BPtr;

result_t f1(APtr) { return 1; }
result_t f2(BPtr) { return 2; }

typedef boost::function <result_t(APtr const&)> funOfA;
typedef boost::function <result_t(BPtr const&)> funOfB;

现在将 funOfB 包装为 funOfA 会看起来像这样:

Now wrapping funOfB as a funOfA would look like this:

funOfA wrapFunOfB(const funOfB f) {
    struct {
        funOfB _f;
        result_t operator()(APtr const& a) const { 
            return _f(boost::static_pointer_cast<B>(a));
        }
    } wrap { f };

    return wrap;
}

现在您可以轻松编写:

int main() {
    F(f1);
    F(wrapFunOfB(f2));
}

简单的C ++ 03演示

在Coliru上直播

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <iostream>

typedef int result_t;
struct A { int i; };
struct B : A { int j; };

typedef boost::shared_ptr<A> APtr;
typedef boost::shared_ptr<B> BPtr;

result_t f1(APtr) { return 1; }
result_t f2(BPtr) { return 2; }

typedef boost::function <result_t(APtr const&)> funOfA;
typedef boost::function <result_t(BPtr const&)> funOfB;

struct Wrapper {
    typedef result_t result_type;
    funOfB _f;

    result_t operator()(APtr const& a) { 
        return _f(boost::static_pointer_cast<B>(a));
    }
};

funOfA wrapFunOfB(const funOfB f) {
    Wrapper wrap = { f };
    return wrap;
}

void F(const funOfA f) {
    APtr a = boost::make_shared<A>();
    APtr b = boost::make_shared<B>();

    //std::cout << "f(a): " << f(a) << "\n"; // UNDEFINED BEHAVIOUR if f wraps a funOfB
    std::cout << "f(b): " << f(b) << "\n";
}

int main() {
    F(f1);
    F(wrapFunOfB(f2));
}

打印

f(b): 1
f(b): 2

问题,警告: dynamic_pointer_cast<>

如果 F 实际上在不是 B 类型的对象上实际上调用了参数,则该 static_cast<>将调用未定义的行为.

PROBLEMS, WARNINGS: dynamic_pointer_cast<>

If F actually invokes the parameter on an object that isn't actually of type B, that static_cast<> will invoke Undefined Behaviour.

如果要防止这种情况发生,请使用 dynamic_pointer_cast ,这要求 A B 类为多态类型.

If you want to protect against that, use dynamic_pointer_cast, which requires the classes A and B to be polymorphic types.

在Coliru上直播

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <iostream>

typedef int result_t;
struct A     { int i; virtual ~A() {} };
struct B : A { int j; };

typedef boost::shared_ptr<A> APtr;
typedef boost::shared_ptr<B> BPtr;

result_t f1(APtr a) { return a?1 : 0; }
result_t f2(BPtr b) { return b?2 : -99; }

typedef boost::function <result_t(APtr const&)> funOfA;
typedef boost::function <result_t(BPtr const&)> funOfB;

struct Wrapper {
    typedef result_t result_type;
    funOfB _f;

    result_t operator()(APtr const& a) { 
        return _f(boost::dynamic_pointer_cast<B>(a));
    }
};

funOfA wrapFunOfB(const funOfB f) {
    Wrapper wrap = { f };
    return wrap;
}

void F(const funOfA f) {
    APtr a = boost::make_shared<A>();
    APtr b = boost::make_shared<B>();

    std::cout << "f(a): " << f(a) << "\n";
    std::cout << "f(b): " << f(b) << "\n";
}

int main() {
    F(f1);
    F(wrapFunOfB(f2));
}

打印

f(a): 1
f(b): 1
f(a): -99
f(b): 2

C ++ 11版本

在这里,事情变得更加优雅.值得注意的是,Wrapper类可以是本地的,也可以是匿名的:

C++11 Version

Things get a little more elegant here. Notably, the Wrapper class can be local, and anonymous:

funOfA wrapFunOfB(const funOfB f) {
    struct {
        typedef result_t result_type;
        funOfB _f;

        result_t operator()(APtr const& a) { 
            return _f(std::dynamic_pointer_cast<B>(a));
        }
    } wrap { f };
    return wrap;
}

下一级别:改为使用lambda:

Next level: use a lambda instead:

funOfA wrapFunOfB(const funOfB f) {
    return [f](APtr const& a) { return f(std::dynamic_pointer_cast<B>(a)); };
}

在Coliru上直播

#include <memory>
#include <functional>
#include <iostream>

typedef int result_t;
struct A     { int i; virtual ~A() {} };
struct B : A { int j; };

typedef std::shared_ptr<A> APtr;
typedef std::shared_ptr<B> BPtr;

result_t f1(APtr a) { return a?1 : 0; }
result_t f2(BPtr b) { return b?2 : -99; }

typedef std::function<result_t(APtr const&)> funOfA;
typedef std::function<result_t(BPtr const&)> funOfB;

funOfA wrapFunOfB(const funOfB f) {
    return [f](APtr const& a) { return f(std::dynamic_pointer_cast<B>(a)); };
}

void F(const funOfA f) {
    APtr a = std::make_shared<A>();
    APtr b = std::make_shared<B>();

    std::cout << "f(a): " << f(a) << "\n";
    std::cout << "f(b): " << f(b) << "\n";
}

int main() {
    F(f1);
    F(wrapFunOfB(f2));
}

代码减少了25%.

这篇关于使用带有参数的boost :: function共享指向派生类的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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