0

解释一下:

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 是一个函子,它的 operator(int) 用 x 的 this 调用 X::foo(int),所以它似乎是特定于 X 的类型,然后当我对 f2/f22 执行相同操作时,它的特定到 Y,那么如何允许 f11 = f22 行?

我实际上想做 f11 = f22 行,但我很惊讶地看到这是允许的,并且我试图理解这不是类型不匹配的原因。

我知道,“使用来源,卢克”,但是 Boost 来源很难理解/理解那里发生的一切。

如果您可以为您的答案显示由模板化扩展的类,那将有所帮助。

我以为它可以通过 void* 铸造或类似的东西来解决这个问题,但这似乎是一种黑客行为,并且在 Boost 下会弯腰到那个水平。那么胡说八道?

顺便说一句,如果你以前没有遇到过这种事情,你至少应该对这个神奇的东西感到惊讶,因为你不能在上面说“x = y”,因为这显然是不允许的,因为它们是不同的类型并且没有 X::operator=(Y&),所以这就是这种惊奇的来源——它是一个巧妙的诡计。

4

1 回答 1

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 中,我将完美转发所有需要的完美转发单参数构造函数。

于 2013-09-21T02:41:14.040 回答