#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));
}