C++ Assigning Values to POD Objects [duplicate]

2020-04-20 07:40发布

问题:

So I read about Plain Old Data classes (POD) , and decided to make my structs POD to hold data. For example, I have

struct MyClass {
    int ID;
    int age;
    double height;
    char[8] Name;
};


Obviously, to assign values to the struct, I can do this:

MyClass.ID = 1;
MyClass.age = 20;
...

But is there anyway to assign raw data, WITHOUT knowing the name of each field?

For example, My program retrieves field value for each column,, and I want to assign the value to the struct, given that i don't know the name of the fields..

MyClass c;

while (MoreColumns()) {
    doSomething( c , GetNextColumn() );    //GetNextColumn() returns some value of POD types
}

I'm assuming there's way to do this using memcpy, or something std::copy,, but Not sure how to start..

Sorry if the question is a bit unclear.

回答1:

You can use aggregate initialization:

MyClass c1 = { 1, 20, 6.0, "Bob" };
MyClass c2;
c2 = MyClass{ 2, 22, 5.5, "Alice" };

There is no general way to loop over the members of a struct or class. There are some tricks to add data and functions to emulate that sort of thing, but they all require additional setup work beyond just declaring the type.



回答2:

Since MyClass is an aggregate, you can use a brace-initializer to initialize all fields in one call, without naming any of them:

   MyClass m  { 
       1,
       2,
       42.0,
       { "Joseph" }
   };

However, given your description, maybe a POD is not a good idea, and you might want to design a class with accessors to set internal fields based on (for example) index columns.



回答3:

Maybe boost::fusion can help you with what you want to archive.
You can use the adapt macro to iterate over a struct. From the example of boost:

struct MyClass 
{
    int ID;
    int age;
    double height;
};

BOOST_FUSION_ADAPT_STRUCT(
    MyClass,
    (int, ID)
    (int, age)
    (double, height)
)

void fillData(int& i)
{
    i = 0;
}

void fillData(double& d)
{
    d = 99;
}

struct MoreColumns
{
    template<typename T>
    void operator()(T& t) const
    {
        fillData(t);
    }
};

int main()
{
    struct MyClass m = { 33, 5, 2.0 };
    std::cout << m.ID << std::endl;
    std::cout << m.age << std::endl;
    std::cout << m.height << std::endl;

    MoreColumns c;
    boost::fusion::for_each(m, c);

    std::cout << m.ID << std::endl;
    std::cout << m.age << std::endl;
    std::cout << m.height << std::endl;
}


回答4:

What you are trying to achieve usually leads to hard-to-read or even unreadable code. However, assuming that you have a genuinely good reason to try to assign (as opposed to initialize) raw data to a field without knowing its name, you could use reinterpret_cast as below (Link here). I don't recommend it, but just want to point out that you have the option.

#include <cstdio>
#include <cstring>

struct Target { // This is your "target"
    char foo[8]; 
};

struct Trap { 
    // The "trap" which lets you manipulate your target
    // without addressing its internals directly.
    // Assuming here that an unsigned occupies 4 bytes (not always holds)
    unsigned i1, i2;
};

int main() {
    Target t;
    strcpy(t.foo, "AAAAAAA");

    // Ask the compiler to "reinterpet" Target* as Trap*
    Trap* tr = reinterpret_cast<Trap*>(&t);

    fprintf(stdout, "Before: %s\n", t.foo);
    printf("%x %x\n", tr->i1, tr->i2);

    // Now manipulate as you please
    // Note the byte ordering issue in i2.
    // on another architecture, you might have to use 0x42424200
    tr->i1 = 0x42424242;
    tr->i2 = 0x00424242;

    printf("After: %s\n", t.foo);

    return 0;
} 

This is just a quick example I came up with, you can figure out how to make it "neater". Note that in the above, you could also access target iteratively, by using an array in "Trap" instead of i1, i2 as I have done above.

Let me reiterate, I don't recommend this style, but if you absolutely must do it, this is an option you could explore.