将 boost::function 与参数一起使用,以共享指向派生 class 的指针
Using boost::function with a parameter to shared pointer to derived class
在 Ubuntu 16.04.
上将 C++ 与 g++ 5.4.0 结合使用
我有一个 class A 和一个派生自 class A 的 class B。函数 f1 将指向 class A 的共享指针作为参数。函数 f2 将指向 class B 的共享指针作为参数,并且 return 与 f1 的类型相同。使用 boost::function,另一个函数 F 将 f1 等函数作为参数。代码如下所示:
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 作为参数。我收到以下错误:
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 得到这个错误,做:
f1_t f = f2;
给出同样的错误。
函数原型没有 co-variance。不同的签名很简单:不同的类型。
在这种情况下,您需要使用转换包装器来包装函数。
让我们创建一些设施定义:
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
看起来像这样:
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 演示
#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<>
将调用 Undefined Behaviour.
如果您想防止这种情况发生,请使用 dynamic_pointer_cast
,这需要 classes A
和 B
是 多态类型.
#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 class 可以是本地的,并且是匿名的:
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:
funOfA wrapFunOfB(const funOfB f) {
return [f](APtr const& a) { return f(std::dynamic_pointer_cast<B>(a)); };
}
#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%。
在 Ubuntu 16.04.
上将 C++ 与 g++ 5.4.0 结合使用我有一个 class A 和一个派生自 class A 的 class B。函数 f1 将指向 class A 的共享指针作为参数。函数 f2 将指向 class B 的共享指针作为参数,并且 return 与 f1 的类型相同。使用 boost::function,另一个函数 F 将 f1 等函数作为参数。代码如下所示:
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 作为参数。我收到以下错误:
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 得到这个错误,做:
f1_t f = f2;
给出同样的错误。
函数原型没有 co-variance。不同的签名很简单:不同的类型。
在这种情况下,您需要使用转换包装器来包装函数。
让我们创建一些设施定义:
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
看起来像这样:
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 演示
#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<>
将调用 Undefined Behaviour.
如果您想防止这种情况发生,请使用 dynamic_pointer_cast
,这需要 classes A
和 B
是 多态类型.
#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 class 可以是本地的,并且是匿名的:
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:
funOfA wrapFunOfB(const funOfB f) {
return [f](APtr const& a) { return f(std::dynamic_pointer_cast<B>(a)); };
}
#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%。