解释一下:
struct X
{
void foo(int arg) { cout << "X" << arg << endl; }
};
struct Y
{
void bar(int arg) { cout << "Y" << arg << endl; }
};
int main(int argc, char *argv[])
{
X x;
Y y;
mem_fun1_t<void, X, int> f1 = std::mem_fun(&X::foo);
boost::function<void (int)> f11 = std::bind1st(f1, &x);
f11(2);
mem_fun1_t<void, Y, int> f2 = std::mem_fun(&Y::bar);
boost::function<void (int)> f22 = std::bind1st(f2, &y);
f22(2);
f11 = f22; // WOW, THIS IS ALLOWABLE
}
Boost如何在封面下工作以允许行f11 = f22?
似乎不寻常,因为f11是一个函子,其运算符(int)用x的这个调用X :: foo(int),所以它似乎是特定于X的类型,然后当我对f2 /执行相同操作时f22具体到Y,那么如何允许f11 = f22?
我实际上想要做f11 = f22行,但我很惊讶地看到这是允许的,并且我试图理解这不是类型不匹配。
我知道,“使用来源,Luke”,但Boost来源很难跟踪/理解那里发生的一切。
如果可以,为了您的答案,可以显示通过模板化扩展的类,这将有所帮助。
我当时认为它是通过虚空*铸造或类似的东西来逃避这一点,但这看起来像是一个黑客,并在Boost之下屈服于那个级别。那么whassup?
顺便说一句,如果你之前没有遇到过这种情况,你至少应该对这一点魔法感到惊讶,因为你不能说上面的“x = y”,因为它们显然是不允许的是不同的类型,没有X :: operator =(Y&amp;),所以这就是这种惊奇的来源 - 它是一个聪明的诡计。答案 0 :(得分:3)
使用的技术称为类型擦除。
我将演示一个用C ++ 11编写的玩具类。许多细节都不准确,但一般技术是:
struct nullary_impl {
virtual void invoke() const = 0;
virtual ~nullary_impl() {}
};
typedef std::shared_ptr<nullary_impl> nullary_pimpl;
struct nullary_func {
nullary_pimpl pimpl;
nullary_func() = default;
nullary_func( nullary_func const& ) = default;
template<typename F>
nullary_func( F const& f );
void operator()() const {
pimpl->invoke();
};
};
template<typename T>
struct nullary_impl_impl:nullary_impl {
T t;
virtual void invoke() const override {
t();
}
nullary_impl_impl( T const& t_ ):t(t_) {}
};
template<typename F>
nullary_func::nullary_func( F const& f ):
pimpl( std::make_shared( nullary_impl_impl<F>(f) )
{}
现在在这种情况下,该类不是模板类,但它是一个模板类并不是重要的部分。
重要的是它有一个模板构造函数。此模板构造函数根据我们构造nullary_func
的类型创建自定义类型对象,然后存储指向自定义类型对象的抽象基础的指针。这个抽象基础有一个我们称之为某种类型的virtual
方法。自定义子类型实现virtual
方法,并在基础类型上调用()
。
现在,shared_ptr
可能不是boost
使用的(可能是某种value_ptr
),而function
中你有template
类和template
构造函数,还有很多其他细节。如果你想获得幻想,你可以实现自己的动态调度而不是virtual
调用。在真正的C ++ 11中,我将完美转发所有需要的完美转发单参数构造函数的问题。