Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何动态设置对象';基于道具名称的属性?_C++_Visual Studio_C++11_Reflection_Visual Studio 2015 - Fatal编程技术网

C++ 如何动态设置对象';基于道具名称的属性?

C++ 如何动态设置对象';基于道具名称的属性?,c++,visual-studio,c++11,reflection,visual-studio-2015,C++,Visual Studio,C++11,Reflection,Visual Studio 2015,我希望我想做的事情会很清楚 我想根据提供的对象的属性从数据库中提取数据,然后用检索到的数据填充这些属性。 例如,如果用户定义了一个类 class Person { public: int Id; string Name; }; 然后,当他调用MyDatabase.Instance.ExecQuery()时,它应该返回Person对象,其中填充了信息 我所做的是:用户应该按照以下方式定义类: class Person : public DBEntity {

我希望我想做的事情会很清楚

我想根据提供的对象的属性从数据库中提取数据,然后用检索到的数据填充这些属性。 例如,如果用户定义了一个类

class Person
{
   public:
      int Id;
      string Name;
};
然后,当他调用
MyDatabase.Instance.ExecQuery()
时,它应该返回
Person
对象,其中填充了信息

我所做的是:用户应该按照以下方式定义类:

class Person : public DBEntity
{
    ENTITIY_PROP(Person , int, Id)
    ENTITIY_PROP(Person , string, Name)
};
定义的宏确保将属性的名称和类型添加到
\u propsMeta
。 现在,如何根据对象的名称设置对象的属性(请参见
ExecQuery

我的初始解决方案
我想添加将属性映射到设置属性的函数的
map
,但我不能有对具有不同签名的函数的引用的
map
。有什么想法吗?如果你认为我需要改变我的设计来完成我需要的-让我知道

template <typename T>
void ExecQuery()
{
    static_assert(std::is_base_of<DBEntity, T>(), "a Class should inherit from DBEntity");

    const auto& props = entity->GetPropsMeta();
    auto row = GetData(props);
    T entity = new T();
    for (const auto& colName : row.Columns)
    {
        string val = row[colName];
        // TODO: SET ENTITY'S PROPERTY colName with val
    }
}

#define ENTITIY_PROP(Class, Type, Name) \
        private: \
            int _##Name; \
        public: \
            class Property_##Name { \
            public: \
                Property_##Name(Class* parent) : _parent(parent) \
                { \
                    _parent->SetPropMeta(#Name, #Type); \
                } \
                Type operator = (Type value) \
                { \
                    _parent->Set##Name(value); \
                    return _parent->Get##Name(); \
                } \
                operator Type() const \
                { \
                    return static_cast<const Class*>(_parent)->Get##Name(); \
                } \
                Property_##Name& operator =(const Property_##Name& other) \
                { \
                    operator=(other._parent->Get##Name()); return *this; \
                }; \
                Property_##Name(const Property_##Name& other) = delete; \
            private: \
                Class* _parent; \
            } Name { this }; \
            \
            Type Get##Name() const { return _##Name; } \
            void Set##Name(int value) { _##Name = value; } \

    class DBEntity
    {
    private:
        std::unordered_map<std::string, std::string> _propsMeta;

    public:
        const std::unordered_map<std::string, std::string>& GetPropsMeta() { return _propsMeta; }    
    };
模板
void ExecQuery()
{
静态_断言(std::is_base_of(),“类应该从DBEntity继承”);
const auto&props=entity->GetPropsMeta();
自动行=获取数据(道具);
T实体=新的T();
for(常量自动和colName:row.Columns)
{
字符串val=行[colName];
//TODO:使用val设置实体的属性colName
}
}
#定义实体属性(类、类型、名称)\
私人:\
国际名称\
公众:\
类属性u##名称{\
公众:\
属性名称(类*父级):\u父级(父级)\
{ \
_父->SetPropMeta(#名称,#类型)\
} \
类型运算符=(类型值)\
{ \
_父项->设置##名称(值)\
return _parent->Get##Name()\
} \
运算符类型()常量\
{ \
返回static_cast(_parent)->Get##Name()\
} \
属性名称和运算符=(常量属性名称和其他)\
{ \
运算符=(其他._parent->Get##Name()),返回*this\
}; \
属性名称(常量属性名称和其他)=删除\
私人:\
*类家长\
}名称{this}\
\
键入Get##Name()const{return###Name;}\
无效集##名称(int值){##名称=值;}\
类DBEntity
{
私人:
std::无序地图_propsMeta;
公众:
const std::无序映射&GetPropsMeta(){return\u propsMeta;}
};

下面是一个使用boost::hana的解决方案:

#include <iostream>
#include <string>
#include <unordered_map>
#include <boost/lexical_cast.hpp>
#include <boost/hana/define_struct.hpp>
#include <boost/hana/for_each.hpp>

namespace hana = boost::hana;

// for simplicity I assume that a row is an unordered_map
using row_type = std::unordered_map<std::string, std::string>;

// this is how your users will be defining classes
struct Person {
    BOOST_HANA_DEFINE_STRUCT(Person,
    (int, Id),
    (std::string, Name));
};

struct Car {
    BOOST_HANA_DEFINE_STRUCT(Car,
    (std::string, Brand),
    (int, HorsePower));
};


// convenient function to extract the row's mapped value and set it directly to the target
template <class T>
void set_data(T& target, std::string key, const row_type& row)
{
    target = boost::lexical_cast<T>(row.at(key));
}


// this is what your database will be doing
template <class Entity>
Entity extract(const row_type& row)
{
    Entity entity;

    // accessors provides a tuple of pairs, where the first element of each pair is a "compile-time" string from which you can extract the key
    // and the second element is a function which returns a reference to appropriate member
    hana::for_each(hana::accessors<Entity>(), [&entity, &row](auto unit)
    {
        std::string property_name = hana::to<const char*>(hana::first(unit));
        set_data(hana::second(unit)(entity), property_name, row);
    });

    return entity;
}

// and now test it
int main()
{
    auto person = extract<Person>({{"Id", "42"},{"Name", "John"}});
    std::cout << person.Id << " " << person.Name << std::endl;

    auto car = extract<Car>({{"Brand", "BMW"},{"HorsePower", "95"}});
    std::cout << car.Brand << " " << car.HorsePower << std::endl;

}
#包括
#包括
#包括
#包括
#包括
#包括
名称空间hana=boost::hana;
//为了简单起见,我假设一行是无序的_映射
使用row_type=std::无序_映射;
//这就是用户定义类的方式
结构人{
增强结构(人、,
(int,Id),
(std::string,Name));
};
结构车{
增强结构(汽车、,
(标准:字符串,品牌),
(整数,马力);
};
//方便的函数,用于提取行的映射值并将其直接设置为目标
模板
无效集合数据(T和目标,标准::字符串键,常量行类型和行)
{
target=boost::词法转换(row.at(key));
}
//这就是您的数据库将要做的
模板
实体提取(常量行类型和行)
{
实体;
//访问器提供一个对元组,其中每对的第一个元素是一个“编译时”字符串,您可以从中提取密钥
//第二个元素是一个函数,它返回对适当成员的引用
hana::for_each(hana::访问器(),[&实体,&行](自动单位)
{
std::string property_name=hana::to(hana::first(unit));
设置数据(hana::第二(单元)(实体)、属性名称、行);
});
返回实体;
}
//现在测试一下
int main()
{
auto person=extract({{“Id”,“42”},{“Name”,“John”});

std::cout是的,您不能有不同签名的函数映射-您需要某种类型的擦除。最简单的解决方案就是将std::any或boost::any作为参数。您是否绝对希望用户像这样创建Person类:
class Person{ENTITY_PROP(Person,int,Id),ENTITY_PROP(Person,string,Name)}
?或者这也行吗?
生成类(Person,(int,Id),(string,Name))
?我知道如何帮助您,但需要使用后一种形式。您可以看看哪种形式允许内省。我曾尝试在“Visual Studio 2015 Update 3”中添加boost标头,但遇到了与c++14兼容的错误。我尝试添加“/std:c++14”但我仍然得到错误。它只在VS2017上工作吗?我根本不使用Visual Studio。您只需要一个c++14编译器(我使用的是g++)