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

时间:2014-02-06 17:24:51

标签: c++ templates c++11 namespaces crtp

简介

我正在尝试使用奇怪的重复模板模式在hdf5组中存储内容。 但我有两个问题:

  1. 如何将成员实现设为私有?
  2. 如何将CRTP与命名空间一起使用?
  3. 我想要什么

    (代码如下)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".
    

1 个答案:

答案 0 :(得分:1)

以下更改似乎有效: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_;
};