digitalmars.D.learn - Default struct constructors if a struct member is a union
- solidstate1991 (20/20) Jun 29 ```d
- Basile B. (21/26) Jun 29 Apprently that works with an anonymous union:
- Nick Treleaven (28/34) Jun 30 Did you mean `U(20)`? The 20 applies to the first field of the
- Basile B. (4/38) Jun 30 That's another solution, that being said, the real problem OP
- Steven Schveighoffer (6/26) Jul 02 Have you tried named parameter construction?
- Steven Schveighoffer (6/8) Jul 02 BTW, this is not true. A constructor does not change the struct
- cc (73/75) Jul 06 ```d
```d union U { int i32; long i64; float f32; double f64; } struct S { TypeEnum type; U data; } S foo0 = S(TypeEnum.Integer32, S(20)); //Ugly, but works S foo1 = S(TypeEnum.Integer64, S(20L)); //Error: cannot implicitly convert expression //ditto for the rest of the members ``` My question is can I initialize structs like these in one line without relying on a second line? My usecase scenario doesn't really allow constructors for the struct, since it's a binding to an external library via C API.
Jun 29
On Saturday, 29 June 2024 at 23:33:41 UTC, solidstate1991 wrote:[...] My question is can I initialize structs like these in one line without relying on a second line? My usecase scenario doesn't really allow constructors for the struct, since it's a binding to an external library via C API.Apprently that works with an anonymous union: ```d enum TypeEnum { Integer32, Integer64, Float32, Float64, } struct S { TypeEnum type; union { int i32; long i64; float f32; double f64; } } S foo0 = S(TypeEnum.Integer32, 20); S foo1 = S(TypeEnum.Integer64, 20L); ```
Jun 29
On Saturday, 29 June 2024 at 23:33:41 UTC, solidstate1991 wrote:S foo0 = S(TypeEnum.Integer32, S(20)); //Ugly, but works S foo1 = S(TypeEnum.Integer64, S(20L)); //Error: cannotDid you mean `U(20)`? The 20 applies to the first field of the union, i32. `U(20L)` also works and (I think) it does the same because of VRP.My question is can I initialize structs like these in one line without relying on a second line? My usecase scenario doesn't really allow constructors for the struct, since it's a binding to an external library via C API.You can use a field initializer: ```d enum TypeEnum { Integer32, Integer64 } union U { int i32; long i64; float f32; double f64; } struct S { TypeEnum type; U data; } S foo0 = S(TypeEnum.Integer32, U(20)); // init i32 S foo1 = S(TypeEnum.Integer64, U(f32: 0.5F)); // struct initializer syntax S foo2 = {TypeEnum.Integer32, {20}}; S foo3 = {TypeEnum.Integer64, {f32: 0.5F}}; // init f32 void main() { assert(foo0.data.i32 == 20); assert(foo3.data.f32 == 0.5F); } ```
Jun 30
On Sunday, 30 June 2024 at 11:23:45 UTC, Nick Treleaven wrote:On Saturday, 29 June 2024 at 23:33:41 UTC, solidstate1991 wrote:That's another solution, that being said, the real problem OP encountered is the classic one of "implict construction", which is not a D thing.S foo0 = S(TypeEnum.Integer32, S(20)); //Ugly, but works S foo1 = S(TypeEnum.Integer64, S(20L)); //Error: cannotDid you mean `U(20)`? The 20 applies to the first field of the union, i32. `U(20L)` also works and (I think) it does the same because of VRP.My question is can I initialize structs like these in one line without relying on a second line? My usecase scenario doesn't really allow constructors for the struct, since it's a binding to an external library via C API.You can use a field initializer: ```d enum TypeEnum { Integer32, Integer64 } union U { int i32; long i64; float f32; double f64; } struct S { TypeEnum type; U data; } S foo0 = S(TypeEnum.Integer32, U(20)); // init i32 S foo1 = S(TypeEnum.Integer64, U(f32: 0.5F)); // struct initializer syntax S foo2 = {TypeEnum.Integer32, {20}}; S foo3 = {TypeEnum.Integer64, {f32: 0.5F}}; // init f32 void main() { assert(foo0.data.i32 == 20); assert(foo3.data.f32 == 0.5F); } ```
Jun 30
On Saturday, 29 June 2024 at 23:33:41 UTC, solidstate1991 wrote:```d union U { int i32; long i64; float f32; double f64; } struct S { TypeEnum type; U data; } S foo0 = S(TypeEnum.Integer32, S(20)); //Ugly, but works S foo1 = S(TypeEnum.Integer64, S(20L)); //Error: cannot implicitly convert expression //ditto for the rest of the members ``` My question is can I initialize structs like these in one line without relying on a second line? My usecase scenario doesn't really allow constructors for the struct, since it's a binding to an external library via C API.Have you tried named parameter construction? ```d S foo2 = S(TypeEnum.Float32, U(f32: 20.0)); ``` -Steve
Jul 02
On Saturday, 29 June 2024 at 23:33:41 UTC, solidstate1991 wrote:My usecase scenario doesn't really allow constructors for the struct, since it's a binding to an external library via C API.BTW, this is not true. A constructor does not change the struct layout or anything about it from the C side. You can safely add the struct constructor (or any other struct member functions) and the struct itself should be C compatible. -Steve
Jul 02
On Saturday, 29 June 2024 at 23:33:41 UTC, solidstate1991 wrote:My question is can I initialize structs like these in one line without relying on a second line?```d template ValueOfUDAType(alias T, alias UDA) { static foreach (uidx, U; __traits(getAttributes, T)) static if (is(typeof(U) == UDA)) enum UDA ValueOfUDAType = U; } struct S { enum TypeEnum { Integer32, Integer64, Float32, Float64, } union U { (TypeEnum.Integer32) int i32; (TypeEnum.Integer64) long i64; (TypeEnum.Float32) float f32; (TypeEnum.Float64) double f64; } TypeEnum type; U data; this(T)(T t) { opAssign(t); } void opAssign(S rhs) { static foreach (idx, field; S.tupleof) { this.tupleof[idx] = rhs.tupleof[idx]; } } void opAssign(T)(T t) { static foreach (idx, field; data.tupleof) static if (is(T == typeof(field))) { type = ValueOfUDAType!(field, TypeEnum); data.tupleof[idx] = t; static assert(!is(typeof(FOUND)), "Assigning type "~fullyQualifiedName!T~" matches multiple candidates "~fullyQualifiedName!U); enum bool FOUND = true; } static assert(is(typeof(FOUND)), "Cannot assign type "~fullyQualifiedName!T~" to "~fullyQualifiedName!U); } T get(T)() { static foreach (idx, field; data.tupleof) static if (is(T == typeof(field))) { enforce(type == ValueOfUDAType!(field, TypeEnum), "Type mismatch requesting "~fullyQualifiedName!T); return data.tupleof[idx]; } } bool is_a(T)() { static foreach (idx, field; data.tupleof) static if (is(T == typeof(field))) { return (type == ValueOfUDAType!(field, TypeEnum)); } } } S s = 3.14f; assert(s.type == S.TypeEnum.Float32); s = 9.17; assert(s.type == S.TypeEnum.Float64); if (s.is_a!double) { writeln(s.get!double); } try { int n = s.get!int; } catch (Exception e) { writeln("Not an int"); } s = 20; assert(s.type == S.TypeEnum.Integer32); s = 40L; assert(s.type == S.TypeEnum.Integer64); ``` Or just use SumType.
Jul 06