Thread overview
Can't convert variables using __traits
Re: Can't convert variables using __traits [CLOSED]
April 18

Hello.
I can't change variable type using __traits.
Code:

    struct Users
    {
    public:
        string login;
        string name;
        string email;
        string icon;
        int type;
    }

    void somefun()
    {
        string[string] test = ["login": "login"];
        Users* user = new Users();
        foreach (member; __traits(allMembers, Users))
            if (member in test)
                __traits(getMember, *user, member) = to!(typeof(member))(test[member]);
    }

I get the error:

>

Error: cannot implicitly convert expression to(test["type"]) of type string to int

Can anoyne explains to me why I can't convert traits member? Without traits I can declare string variable and convert it to int succesfully.

April 18

On Monday, 18 April 2022 at 11:31:29 UTC, Wusiki jeronii wrote:

>

Hello.
I can't change variable type using __traits.
Code:

    struct Users
    {
    public:
        string login;
        string name;
        string email;
        string icon;
        int type;
    }

    void somefun()
    {
        string[string] test = ["login": "login"];
        Users* user = new Users();
        foreach (member; __traits(allMembers, Users))
            if (member in test)
                __traits(getMember, *user, member) = to!(typeof(member))(test[member]);
    }

I get the error:

>

Error: cannot implicitly convert expression to(test["type"]) of type string to int

Can anoyne explains to me why I can't convert traits member? Without traits I can declare string variable and convert it to int succesfully.

Hello,
the error happens because __traits(allMembers) doesn't return actual struct members, it returns their names as strings. Because of that typeof(member) will always return string, and your code becomes equivalent to:

foreach(member; __traits(allMembers, Users))
    if(member in test)
        __traits(getMember, *user, member) = to!string(test[member]);

then the compiler sees that you're attempting to assign a string to user.type and gives an implicit conversion error.

The solution is to apply typeof to the actual member, not its name:

__traits(getMember, *user, member) = to!(typeof(__traits(getMember, *user, member)))(test[member]);

Obviously this is quite verbose.

You can improve the readability a bit by introducing a helper function:

void setFromString(T)(out T member, string value) {
    member = to!T(value);
}

//later:
foreach(member; __traits(allMembers, Users))
    if(member in test)
        __traits(getMember, *user, member).setFromString(test[member]);
April 18

On Monday, 18 April 2022 at 12:20:11 UTC, Krzysztof Jajeśnica wrote:

>

On Monday, 18 April 2022 at 11:31:29 UTC, Wusiki jeronii wrote:

>

[...]

Hello,
the error happens because __traits(allMembers) doesn't return actual struct members, it returns their names as strings. Because of that typeof(member) will always return string, and your code becomes equivalent to:

foreach(member; __traits(allMembers, Users))
    if(member in test)
        __traits(getMember, *user, member) = to!string(test[member]);

then the compiler sees that you're attempting to assign a string to user.type and gives an implicit conversion error.

[...]

Oohh. I've understood. Thanks

April 18

On Monday, 18 April 2022 at 11:31:29 UTC, Wusiki jeronii wrote:

>

[...]

You can use .tupleof too to access or foreach over individual members of a struct or a class.

void somefun()
{
    string[string] test = ["login" : "login", "type" : "42"];
    Users* user = new Users();

    assert(user.login == "");
    assert(user.type == 0);

    foreach (i, ref member; user.tupleof)
    {
        enum memberName = __traits(identifier, Users.tupleof[i]);

        if (memberName in test)
        {
            member = to!(typeof(member))(test[memberName]);
        }
    }

    assert(user.login == "login");
    assert(user.type == 42);
}