2016-12-26 7 views
6

假设你有下面的代码:如何设计一个可序列化的类,以便任何非序列化的属性导致编译时错误?

class A { 
    bool _attribute1; 
}; 

// Arbitrarily using std::string, not the point of this question 
std::string serialize(const A&); 

现在开发人员增加了一个新bool _attribute2class A和忘记更新serialize功能,从而导致错误在运行时。 (已经在那里?)

有没有办法将这个问题变成编译时错误?由于C++不支持反射,我觉得这是不可能的,但我可能会错过一些东西。

+0

我不认为这是可能的。 –

+1

我能想到的唯一的事情是在sizeof(A)上的某个静态断言。因此,如果有东西被添加,某些东西将无法编译,直到新的类成员被序列化并且相应地调整静态断言。 –

+0

您可以将自定义脚本或程序添加到您的生成文件或IDE预生成步骤中,以检查该类的所有成员是否都包含在该函数中。 – wally

回答

2

如果您使用的是C++ 1Z你可以利用结构结合:

struct S { 
    bool b; 
    //bool c; // causes error 
}; 

int main() { 
    S s; 
    auto [x] = s; 
    (void)x; 
} 

[live demo]

+0

不错。你会推荐序列化函数使用'x'吗? – wally

+0

@Muscampester只要你计划序列化只有公共领域的类,它是相对容易执行 –

+0

我看到这也适用于'自动&'。私人会员可以做些什么? – wally

2

下一个应该与C++ 11的工作。
有点棘手的确,它基于的@SamVarshavchik评论:

#include<cstddef> 
#include<functional> 

template<std::size_t> struct Int { int i; }; 
template<std::size_t> struct Char { char c; }; 
template<std::size_t> struct Bool { bool c; }; 

template<typename, template<std::size_t> class...> 
struct Base; 

template<template<std::size_t> class... T, std::size_t... I> 
struct Base<std::index_sequence<I...>, T...>: T<I>... {}; 

template<template<std::size_t> class... T> 
struct Check final: Base<std::make_index_sequence<sizeof...(T)>, T...> {}; 

class A final { 
    bool _attribute1; 
    bool _attribute2; 
private: 
    char _attribute3; 
    // int _attribute4; 
}; 

void serialize(const A &) { 
    static_assert(sizeof(A) == sizeof(Check<Bool, Bool, Char>), "!"); 
    // do whatever you want here... 
} 

int main() { 
    serialize(A{}); 
} 

的基本思想是列出所有类型的数据成员和定义一个新的类型,从他们一个mixin。那么这是一个把static_assert放在正确的地方的问题。
请注意,也会考虑私人数据成员。

存在一些可能会破坏它的角落案例,但也许它可以为您的真实代码工作。


作为一个侧面说明,它可以进一步简化,如果C++ 14是一个选项:

#include<cstddef> 

template<typename... T> 
constexpr std::size_t size() { 
    std::size_t s = 0; 
    std::size_t _[] = { s += sizeof(T)... }; 
    (void)_; 
    return s; 
} 

class A final { 
    bool _attribute1; 
    bool _attribute2; 
private: 
    char _attribute3; 
    // int _attribute4; 
}; 

void serialize(const A &) { 
    static_assert(sizeof(A) == size<bool, bool, char>(), "!"); 
    // ... 
} 

int main() { 
    serialize(A{}); 
} 
0

如果你注定要使用C++ 11,仍然您有兴趣序列化只有公共领域,你可以创建特质测试,如果该类型可以通过列表初始化构造与给定的参数类型,但连一个也没有更多的(任何类型):

#include <type_traits> 

struct default_param { 
    template <class T> 
    operator T(); 
}; 

template <class T, class...> 
using typer = T; 

template <class, class, class... Args> 
struct cannot_one_more: std::true_type {}; 

template <class Tested, class... Args> 
struct cannot_one_more<typer<void, decltype(Tested{std::declval<Args>()..., default_param{}})>, Tested, Args...>: std::false_type { 
}; 

template <class...> 
struct is_list_constructable: std::false_type {}; 

template <class Tested, class... Args> 
struct is_list_constructable<Tested(Args...)>: is_list_constructable<void, Tested, Args...> { }; 

template <class Tested, class... Args> 
struct is_list_constructable<typer<void, decltype(Tested{std::declval<Args>()...}), typename std::enable_if<cannot_one_more<void, Tested, Args...>::value>::type>, Tested, Args...>: std::true_type { }; 

struct S { 
    bool b; 
    //bool c; // causes error 
}; 

int main() { 
    static_assert(is_list_constructable<S(bool)>::value, "!"); 
} 

[live demo]

相关问题