Merge 3be2e1b28f into 39f737443b
This commit is contained in:
commit
38f81b1193
@ -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;
|
||||
```
|
||||
@ -34,7 +34,7 @@
|
||||
namespace YAML {
|
||||
class Binary;
|
||||
struct _Null;
|
||||
template <typename T>
|
||||
template <typename T, typename Enable>
|
||||
struct convert;
|
||||
} // namespace YAML
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
92
test/integration/convert_partial_specialization_test.cpp
Normal file
92
test/integration/convert_partial_specialization_test.cpp
Normal 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
|
||||
Loading…
Reference in New Issue
Block a user