#include <memory>class AnyWrapper {public:virtual void printf(std::ostream &out) = 0;virtual ~AnyWrapper() = default;};template<class T>class AnyStorage : AnyWrapper {public:explicit AnyStorage(const T &obj) :obj(obj) {}void printf(std::ostream &out) override {out << obj;}private:T obj;};class Any {private:std::shared_ptr<AnyWrapper> ptr;public:template<class T>Any(const T &obj) {ptr.reset((AnyWrapper*)new AnyStorage<T>(obj));}friend std::ostream &operator << (std::ostream &out, const Any &any) {any.ptr -> printf(out);return out;}};int main() {Any a(0);Any b('1');std::vector<Any> vec;vec.push_back(1);vec.push_back(2);for (const Any &x : vec) {std::cout << x << std::endl;}return 0;}
Any 类型存储的是由子类 AnyStorage 转成父类 AnyWrapper 类型的指针。首先要明白要存储数据就要进行声明,而声明必须得知道一个具体的类型。这也是为什么实际存储对象的 AnyStorage 需要一个模板参数,而这个模板参数往往是模板推断出来的。
函数指针
三种存储函数的方式,函数指针,对象重载,lambda 表达式。标准库还有兼容上面三种的类型的 std::function。
int triple(int x) {return 3*x;}struct Tripler {int operator()(int x) {return 3*x;}};std::function<int (int)> function(triple);std::function<int (int)> object(Tripler {});std::function<int (int)> lambda([](int x) {return 3*x;});
std::function
int triple(int x) {return 3*x;}struct Tripler {int operator()(int x) {return 3*x;}};template<typename Ret, typename ...Args>class MyFunctionWrapper {public:virtual Ret operator() (Args ...args) = 0;virtual ~MyFunctionWrapper() = default;};template<typename T, typename Ret, typename ...Args>class MyFunctionStorage : MyFunctionWrapper<Ret, Args...> {public:Ret operator() (Args ...args) {return object(std::forward<Args...>(args...));}MyFunctionStorage(const T& obj): object(obj) {}private:T object;};template<class Ret, class ...Args>class MyFunction {public:template<class T>explicit MyFunction(const T &func) {ptr.reset((MyFunctionWrapper<Ret, Args...>*)new MyFunctionStorage<T, Ret, Args...>(func));}Ret operator() (Args ...args) {return (*ptr)(std::forward<Args...>(args...));}private:std::unique_ptr<MyFunctionWrapper<Ret, Args...>> ptr;};int main() {MyFunction<int, int> my(triple);MyFunction<int, int> my1(Tripler{});MyFunction<int, int> my2([](int x) {return 3*x;});std::cout << my(3) << std::endl;std::cout << my1(3) << std::endl;std::cout << my2(3) << std::endl;return 0;}
- 为什么 MyFunction 需要模板参数?为什么 MyFunction 的构造函数需要模板参数?
上面说到存储数据就要进行声明,声明需要具体的函数类型,构造函数接受实际的函数指针类型,用于 MyFunctionStorage 存储 func 指针(构造函数使用模板来推断),同时由于函数调用符的重载需要用到 class Ret, class …Args 模板参数,所以三个类都需要用到 class Ret, class …Args 这些模板参数。
- 为什么 MyFunction
my(&triple); 中的 triple 需要加 & ?
MyFunction
std::decay_t
要想达到标准库的效果,我们可以使用 std::decay_t 来将函数退化成函数指针,如果是 C 标准的字符数组也会退化成字符指针。
explicit MyFunction(const T &func) {ptr.reset((MyFunctionWrapper<Ret, Args...>*)new MyFunctionStorage<std::decay_t<T>, Ret, Args...>(func));}
