boost::any replacement for the code below
我希望摆脱对我的代码的 boost 依赖。我有以下结构构造。在代码中的另一个位置调用和使用此结构时,使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | struct Properties { public: Properties() {} Properties(const std::string &s, const boost::any & p) { name = s; value = p; } template <typename T> Properties(T n) { value = n; } boost::any value; std::string name; }; |
只是为了好玩,我想我会创建一个极简的任何实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | ////////////////////////////////////////// // my_any.hpp #include <memory> #include <stdexcept> struct my_any { my_any() = default; template <typename T> my_any(T const& v) : _storage(new storage< T >(v)) { } my_any(my_any const& other) : _storage(other._storage? std::move(other._storage->clone()) : nullptr) {} void swap(my_any& other) { _storage.swap(other._storage); } friend void swap(my_any& a, my_any& b) { a.swap(b); }; my_any& operator=(my_any other) { swap(other); return *this; } // todo move semantics private: struct storage_base { virtual std::unique_ptr<storage_base> clone() = 0; virtual ~storage_base() = default; }; template <typename T> struct storage : storage_base { T value; explicit storage(T const& v) : value(v) {} std::unique_ptr<storage_base> clone() { return std::unique_ptr<storage_base>(new storage< T >(value)); } }; std::unique_ptr<storage_base> _storage; template<typename T> friend T & any_cast(my_any &); template<typename T> friend T const& any_cast(my_any const&); }; template <typename T> T& any_cast(my_any& a) { if (auto p = dynamic_cast<my_any::storage< T >*>(a._storage.get())) return p->value; else throw std::bad_cast(); } template <typename T> T const& any_cast(my_any const& a) { if (auto p = dynamic_cast<my_any::storage< T > const*>(a._storage.get())) return p->value; else throw std::bad_cast(); } |
然后您可以按照您的用例所示的方式使用它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | struct Properties { public: Properties(const std::string &s="", const my_any& p={}) : name(s), value(p) {} template <typename T> Properties(T n) { value = n; } std::string name; my_any value; }; #include <vector> #include <iostream> typedef std::vector<Properties> Props; int main() { Props v; v.emplace_back("bye", 42); v.emplace_back("vector", v); std::cout <<"v.size():" << v.size() <<"\ "; std::cout <<"v[0].value:" << any_cast<int>(v[0].value) <<"\ "; std::cout <<"v[1].value.size():" << any_cast<Props>(v[1].value).size() <<"\ "; v[0].value = v; try { std::cout <<"v[0].value:" << any_cast<int>(v[0].value) <<"\ "; } catch(std::exception const& e) { std::cout << e.what() <<" exception caught, ok!\ "; } std::cout <<"v[0].value.size():" << any_cast<Props>(v[0].value).size() <<"\ "; } |
查看输出 Live On Coliru
1 2 3 4 5 6 | Properties p("int", 42); std::cout << boost::any_cast<int>(p.value) << '\ '; p = Properties("string", std::string("hello")); std::cout << boost::any_cast<std::string>(p.value) << '\ '; |
您不能只是将上面的类转换为模板并获得相同的功能。如果这样做,您将只能存储一种类型的值。而且您必须将整个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | template<typename T> struct Properties { public: Properties() {} Properties(std::string s, T p) : name(std::move(s)) // should use initialization list instead , value(std::move(p)) // of assignment within the body {} Properties(T n) : value(std::move(n)) {} std::string name; T value; }; |
但是,我上面发布的代码现在是非法的。
1 2 3 4 5 6 | Properties<int> p("int", 42); std::cout << p.value << '\ '; // p = Properties<std::string>("string", std::string("hello")); // will not compile because Properties<int> and Properties<std::string> are // distinct types |
如果这些限制没问题,那么修改后的定义应该适合你。