#include <type_traits>
#include <string>
#include <iostream>
// Данные
struct Base
{};
struct A: Base
{
std::string name = "name_A";
};
struct B: Base
{
std::string name = "name_B";
std::string description = "desc_B";
};
struct C: Base
{
std::string description = "desc_C";
};
class MetaAll;
class MetaName
{
public:
inline const std::string& name() const { return *_name; }
public:
MetaName()
: _name{&_const_name_empty}
{};
template<
class T,
std::enable_if_t<!std::is_base_of<MetaAll, T>::value>* = nullptr // for VC
>
explicit MetaName(const T& t)
: _name{&t.name}
{}
MetaName(const MetaName&) = default;
MetaName& operator=(const MetaName&) = default;
private:
static const std::string _const_name_empty;
const std::string* _name;
};
const std::string MetaName::_const_name_empty;
class MetaDescription
{
public:
inline const std::string& description() const { return *_description; }
public:
MetaDescription()
: _description{&_const_description_empty}
{};
template<
class T,
std::enable_if_t<!std::is_base_of<MetaAll, T>::value>* = nullptr // for VC
>
explicit MetaDescription(const T& t)
: _description{&t.description}
{}
MetaDescription(const MetaDescription&) = default;
MetaDescription& operator=(const MetaDescription&) = default;
private:
static const std::string _const_description_empty;
const std::string* _description;
};
const std::string MetaDescription::_const_description_empty;
struct FieldNameTag {};
struct FieldDescriptionTag {};
const FieldNameTag FieldName;
const FieldDescriptionTag FieldDescription;
class MetaAll: public MetaName, public MetaDescription
{
public:
MetaAll() = default;
MetaAll(const MetaAll&) = default;
MetaAll& operator=(const MetaAll&) = default;
template<class T>
MetaAll(const T& t, FieldNameTag)
: MetaName(t)
, MetaDescription()
{}
template<class T>
MetaAll(const T& t, FieldDescriptionTag)
: MetaName()
, MetaDescription(t)
{}
template<class T>
MetaAll(const T& t, FieldNameTag, FieldDescriptionTag)
: MetaName(t)
, MetaDescription(t)
{}
};
int main()
{
const A a;
const B b;
const C c;
for (MetaName meta : {MetaName(a), MetaName(b)})
{
std::cout << meta.name() << std::endl;
}
for (MetaDescription meta : {MetaDescription(b), MetaDescription(c)})
{
std::cout << meta.description() << std::endl;
}
for (MetaAll meta : {MetaAll(a, FieldName), MetaAll(b, FieldName, FieldDescription), MetaAll(c, FieldDescription)})
{
std::cout << meta.name() << " <-> " << meta.description() << std::endl;
}
// MetaAll meta(a, FieldDescription); -> Compile time error
return 0;
}