【问题标题】:Curiously Recurring Template Pattern -- Inheritance and friends奇怪地重复出现的模板模式——继承和朋友
【发布时间】:2014-02-06 17:24:51
【问题描述】:

简介

我正在尝试使用 Curiously Recurring Template Pattern 将内容存储在 hdf5 组中。 但是我有两个问题:

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

我想要什么

(代码如下)hdf5::Group代表一个hdf5组,可以存储数据集。hdf5::Storable是一个CRTP模板类。函数hdf5::store 应该接受一个组和一个可存储对象并调用该对象的实现。所有这些都应该在命名空间hdf5 中以保持干净。

A 实现了一个可存储的。它位于hdf5 命名空间之外(例如,全局或其他命名空间)。实现方法A::store应该是私有的,保证大家都用hdf5::store代替。

我有什么

有问题的部分有cmets指出问题。

#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".

【问题讨论】:

  • 友谊不是传递的。
  • 嗯,友谊不是传递性的,但在这种情况下,这是一个友谊没有传递给你的后代类的问题。据我了解,友谊是逐级产生的。
  • @πάνταῥεῖ 为什么要关联AGroupA 可以是任何东西,例如矩阵类、数据表或复杂对象...hdf5::store 实际上是在朋友声明中定义的。

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


【解决方案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_;
};

【讨论】:

  • 谢谢,这行得通。你知道有没有办法写这个,这样你就不需要A中的朋友声明了?除了将A::store 公开之外。据我了解您的解决方案以及我在其他地方阅读的内容,朋友不会被继承。它们可以有效继承的唯一方法是通过虚拟方法,对吗?
  • 如果您创建virtual hdf5::Storable&lt;A&gt;::store(hdf5::Group &amp;grp) constA::Store 可以通过hdf5::Storable&lt;A&gt; 调用,如下static_cast&lt;const hdf5::Storable&lt;A&gt;&amp;&gt;(obj).store(grp);,您可以删除friend
  • works indeed。但是,它需要公共继承,并以 vtable 为代价。但是相比实际存储,vtable大概可以忽略不计了……
猜你喜欢
  • 1970-01-01
  • 2012-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多