至尊宝的传说
因为类型擦除还包括如何复制类型(在该答案中,函数对象将不可复制构造)。这些行为function除了函子数据外,还存储在对象中。在Ubuntu 14.04 gcc 4.8的STL实现中使用的技巧是编写一个泛型函数,使用每种可能的函子类型对其进行专用化,然后将其转换为通用函数指针类型。因此,类型信息被擦除。我已经整理了一个简化的版本。希望对你有帮助#include <iostream>#include <memory>template <typename T>class function;template <typename R, typename... Args>class function<R(Args...)>{ // function pointer types for the type-erasure behaviors // all these char* parameters are actually casted from some functor type typedef R (*invoke_fn_t)(char*, Args&&...); typedef void (*construct_fn_t)(char*, char*); typedef void (*destroy_fn_t)(char*); // type-aware generic functions for invoking // the specialization of these functions won't be capable with // the above function pointer types, so we need some cast template <typename Functor> static R invoke_fn(Functor* fn, Args&&... args) { return (*fn)(std::forward<Args>(args)...); } template <typename Functor> static void construct_fn(Functor* construct_dst, Functor* construct_src) { // the functor type must be copy-constructible new (construct_dst) Functor(*construct_src); } template <typename Functor> static void destroy_fn(Functor* f) { f->~Functor(); } // these pointers are storing behaviors invoke_fn_t invoke_f; construct_fn_t construct_f; destroy_fn_t destroy_f; // erase the type of any functor and store it into a char* // so the storage size should be obtained as well std::unique_ptr<char[]> data_ptr; size_t data_size;public: function() : invoke_f(nullptr) , construct_f(nullptr) , destroy_f(nullptr) , data_ptr(nullptr) , data_size(0) {} // construct from any functor type template <typename Functor> function(Functor f) // specialize functions and erase their type info by casting : invoke_f(reinterpret_cast<invoke_fn_t>(invoke_fn<Functor>)) , construct_f(reinterpret_cast<construct_fn_t>(construct_fn<Functor>)) , destroy_f(reinterpret_cast<destroy_fn_t>(destroy_fn<Functor>)) , data_ptr(new char[sizeof(Functor)]) , data_size(sizeof(Functor)) { // copy the functor to internal storage this->construct_f(this->data_ptr.get(), reinterpret_cast<char*>(&f)); } // copy constructor function(function const& rhs) : invoke_f(rhs.invoke_f) , construct_f(rhs.construct_f) , destroy_f(rhs.destroy_f) , data_size(rhs.data_size) { if (this->invoke_f) { // when the source is not a null function, copy its internal functor this->data_ptr.reset(new char[this->data_size]); this->construct_f(this->data_ptr.get(), rhs.data_ptr.get()); } } ~function() { if (data_ptr != nullptr) { this->destroy_f(this->data_ptr.get()); } } // other constructors, from nullptr, from function pointers R operator()(Args&&... args) { return this->invoke_f(this->data_ptr.get(), std::forward<Args>(args)...); }};// examplesint main(){ int i = 0; auto fn = [i](std::string const& s) mutable { std::cout << ++i << ". " << s << std::endl; }; fn("first"); // 1. first fn("second"); // 2. second // construct from lambda ::function<void(std::string const&)> f(fn); f("third"); // 3. third // copy from another function ::function<void(std::string const&)> g(f); f("forth - f"); // 4. forth - f g("forth - g"); // 4. forth - g // capture and copy non-trivial types like std::string std::string x("xxxx"); ::function<void()> h([x]() { std::cout << x << std::endl; }); h(); ::function<void()> k(h); k(); return 0;}STL版本中也有一些优化在construct_f和destroy_f混合成一个函数指针(以告诉做什么额外的参数),以节省一些字节原始指针用于将functor对象与函数指针一起存储在中union,因此,当function从函数指针构造对象时,它将直接存储在union而不是堆空间中也许STL的实施不是最好的解决方案,因为我听说一些更快的实施。但是,我相信基本机制是相同的。