奇怪的重复模板模式 - 继承和朋友

Curiously Recurring Template Pattern -- Inheritance and friends

本文关键字:模式 继承 朋友      更新时间:2023-10-16

into

我正在尝试使用奇怪的重复模板模式,以使其在HDF5组中可存储。但是我有两个问题:

  1. 如何使会员实施私有?
  2. 如何将CRTP与名称空间使用?

我想要的

(遵循代码)hdf5::Group代表HDF5组,并且可以存储数据集。hdf5::Storable是CRTP模板类。函数hdf5::store应采用一个组和一个可存储的对象,并调用对象的实现。所有这些都应在命名空间hdf5内保持清洁。

A实现了存储。它生活在hdf5名称空间(例如全局或其他名称空间)之外。实现方法A::store应该是私有的,以确保每个人都使用hdf5::store

我拥有的

所讨论的部分有评论指出问题。

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

预期输出

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

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_;
};