This commit is contained in:
Benjamin Navarro 2025-01-28 04:52:58 +00:00 committed by GitHub
commit 38f81b1193
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 170 additions and 2 deletions

View File

@ -198,4 +198,80 @@ Then you could use `Vec3` wherever you could use any other type:
YAML::Node node = YAML::Load("start: [1, 3, 0]");
Vec3 v = node["start"].as<Vec3>();
node["end"] = Vec3(2, -1, 0);
```
## Partial specialization
If you need to specialize the `convert` struct for a set of types instead of just one you can use partial specialization with the help of `std::enable_if` (SFINAE).
Here is a small example showing how to partially specialize the `convert` struct for all types deriving from a base class:
```cpp
// Base class
class A
{
public:
A() = default;
A(int a) : a{a} {}
// virtual load/emit methods
virtual void load(const YAML::Node &node) {
a = node["a"].as<int>();
}
virtual YAML::Node emit() const {
YAML::Node node;
node["a"] = a;
return node;
}
int a;
};
// Derived class
class B : public A
{
public:
B() = default;
B(int a, int b) : A{a}, b{b} {}
// override virtual load/emit methods
virtual void load(const YAML::Node &node) override {
A::load(node);
b = node["b"].as<int>();
}
virtual YAML::Node emit() const override {
YAML::Node node = A::emit();
node["b"] = b;
return node;
}
int b;
};
// Implementation of convert::{encode,decode} for all classes derived from or being A
namespace YAML {
template<typename T>
struct convert<T, typename std::enable_if<std::is_base_of<A, T>::value>::type> {
static Node encode(const T &rhs) {
Node node = rhs.emit();
return node;
}
static bool decode(const Node &node, T &rhs) {
rhs.load(node);
return true;
}
};
}
```
Which can then be use like this:
```cpp
YAML::Node node = YAML::Load("{a: 1, b: 2}");
B b = node.as<B>();
b.a = 12;
b.b = 42;
node = b;
```

View File

@ -34,7 +34,7 @@
namespace YAML {
class Binary;
struct _Null;
template <typename T>
template <typename T, typename Enable>
struct convert;
} // namespace YAML

View File

@ -141,7 +141,7 @@ YAML_CPP_API bool operator==(const Node& lhs, const Node& rhs);
YAML_CPP_API Node Clone(const Node& node);
template <typename T>
template <typename T, typename Enable = void>
struct convert;
}

View File

@ -0,0 +1,92 @@
#include "yaml-cpp/emitterstyle.h"
#include "yaml-cpp/eventhandler.h"
#include "yaml-cpp/yaml.h" // IWYU pragma: keep
#include "gtest/gtest.h"
// Base class
class A {
public:
A() = default;
A(int a) : a{a} {}
// virtual load/emit methods
virtual void load(const YAML::Node &node) { a = node["a"].as<int>(); }
virtual YAML::Node emit() const {
YAML::Node node;
node["a"] = a;
return node;
}
int a{};
};
// Derived class
class B : public A {
public:
B() = default;
B(int a, int b) : A{a}, b{b} {}
// override virtual load/emit methods
virtual void load(const YAML::Node &node) override {
A::load(node);
b = node["b"].as<int>();
}
virtual YAML::Node emit() const override {
YAML::Node node = A::emit();
node["b"] = b;
return node;
}
int b{};
};
// Implementation of convert::{encode,decode} for all classes derived from or
// being A
namespace YAML {
template <typename T>
struct convert<T, typename std::enable_if<std::is_base_of<A, T>::value>::type> {
static Node encode(const T &rhs) {
Node node = rhs.emit();
return node;
}
static bool decode(const Node &node, T &rhs) {
rhs.load(node);
return true;
}
};
namespace {
TEST(ConvertPartialSpecializationTest, EncodeBaseClass) {
Node n(Load("{a: 1}"));
A a = n.as<A>();
EXPECT_EQ(a.a, 1);
}
TEST(ConvertPartialSpecializationTest, EncodeDerivedClass) {
Node n(Load("{a: 1, b: 2}"));
B b = n.as<B>();
EXPECT_EQ(b.a, 1);
EXPECT_EQ(b.b, 2);
}
TEST(ConvertPartialSpecializationTest, DecodeBaseClass) {
A a(1);
Node n;
n = a;
EXPECT_EQ(a.a, n["a"].as<int>());
}
TEST(ConvertPartialSpecializationTest, DecodeDerivedClass) {
B b(1, 2);
Node n;
n = b;
EXPECT_EQ(b.a, n["a"].as<int>());
EXPECT_EQ(b.b, n["b"].as<int>());
}
} // namespace
} // namespace YAML