Curiously Recurring Template Pattern — Inheritance and friends
简介如何使成员实现私有化?
如何将CRTP与命名空间一起使用?
我正在尝试使用奇怪的重复模板模式,以使HDF5组中的内容可存储。但我有两个问题:
我想要什么
(代码如下)
有问题的部分有指出问题的评论。
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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | #include <string> #include <iostream> namespace hdf5 { /// A group can contain other groups, and datasets. class Group { public: /// Create a group under a parent group. Group(Group* parent, const std::string &name) : parent_(parent), name_(name) { std::cout <<"Creating group "" << name <<"""; if (parent != nullptr) std::cout <<" under "" << parent->name_ <<"""; std::cout <<"." << std::endl; }; /// Create a root group. Group() : Group(nullptr,"root") { } /// Create a dataset inside. void create_dataset(const std::string &name) { std::cout <<"Creating dataset "" << name <<""" <<" under "" << name_ <<""." << std::endl; } private: Group *parent_; std::string name_; }; /** Abstraction of a storable class. * * Curiously recurring template pattern. * Makes it possible to write * * store(grp, obj); * */ template<class Derived> class Storable { friend void hdf5::store(hdf5::Group &grp, const Derived &obj) { obj.store(grp); } }; } // namespace hdft /// Some data class that should be storable. class A : private hdf5::Storable<A> { public: A(const std::string &name) : name_(name) { } /* * Why can't I make it private? `store` should be friend. * * test.cc: In instantiation of ‘void hdf5::store(hdf5::Group&, const A&)’: * test.cc:104:19: required from here * test.cc:72:10: error: ‘void A::store(hdf5::Group&) const’ is private * void store(hdf5::Group &grp) const { * ^ * test.cc:45:9: error: within this context * obj.store(grp); * ^ */ // private: public: /// Implementation of the storage void store(hdf5::Group &grp) const { grp.create_dataset(name_); } private: std::string name_; }; /// Demonstration. int main(void) { hdf5::Group root, grpa(&root, std::string("group_a")), grpb(&root, std::string("group_b")); A a1(std::string("A1")), a2(std::string("A2")); /* * This is what I want, but it doesn't compile: * * test.cc: In function ‘int main()’: * test.cc:96:5: error: ‘store’ is not a member of ‘hdf5’ * hdf5::store(root, a1); * ^ */ // hdf5::store(root, a1); // hdf5::store(root, a2); // hdf5::store(grpa, a1); // hdf5::store(grpb, a2); /* * This OTOH compiles and runs. */ store(root, a1); store(root, a2); store(grpa, a1); store(grpb, a2); } |
预期产量
1 2 3 4 5 6 7 | Creating group"root". Creating group"group_a" under"root". Creating group"group_b" under"root". Creating dataset"A1" under"root". Creating dataset"A2" under"root". Creating dataset"A1" under"group_a". Creating dataset"A2" under"group_b". |
以下更改似乎有效:https://ideone.com/crulkb
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 | namespace hdf5 { // Previous stuff template <class Derived> void store(hdf5::Group &grp, const Derived&obj); template<class Derived> class Storable { static void store(hdf5::Group &grp, const Derived&obj) { obj.store(grp); } friend void hdf5::store<>(hdf5::Group &grp, const Derived&obj); }; template <class Derived> void store(hdf5::Group &grp, const Derived&obj) { Storable<Derived>::store(grp, obj); } } // namespace hdf5 /// Some data class that should be storable. class A : private hdf5::Storable<A> { friend class hdf5::Storable<A>; private: /// Implementation of the storage void store(hdf5::Group &grp) const { grp.create_dataset(name_); } private: std::string name_; }; |