Я пытаюсь использовать Curiously Recurring Template Pattern, чтобы сделать вещи доступными для хранения в группах hdf5. Но у меня две проблемы:
(Код следует) 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_;
};
A
? Кроме того, чтобы сделать A::store
публичным, то есть. Как я понимаю ваше решение и то, что я читаю в другом месте, друзья не наследуются. Единственный способ, которым они могут быть эффективно унаследованы, это через виртуальные методы, верно?
virtual hdf5::Storable<A>::store(hdf5::Group &grp) const
, A::Store
может быть hdf5::Storable<A>
через hdf5::Storable<A>
как static_cast<const hdf5::Storable<A>&>(obj).store(grp);
и вы можете удалить friend
.