www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Accessing part of a struct in an easy way

reply Paolo Invernizzi <paolo.invernizzi gmail.com> writes:
I've struct like that:

struct Foo {
     int a_1; float a_2; string a_3;
     string b_1; double b_2;
}

I would like to transparently access that like:

foo.a.first
foo.b.second = "baz";

with an helper like:

auto a(...) { ... }
auto b(...) { ... }

that can be used also in functions that are expecting it:

void worksOnA( .... ) { }
void worksOnB( .... ) { }

auto foo = Foo( ... )
foo.a.worksOnA();
foo.b.worksOnB();

But I'm struggling in finding a good way to do it...
Suggestions?

Thanks!
/Paolo
Jul 03 2017
parent reply vit <vit vit.vit> writes:
On Monday, 3 July 2017 at 13:53:45 UTC, Paolo Invernizzi wrote:
 I've struct like that:

 struct Foo {
     int a_1; float a_2; string a_3;
     string b_1; double b_2;
 }

 I would like to transparently access that like:

 foo.a.first
 foo.b.second = "baz";

 with an helper like:

 auto a(...) { ... }
 auto b(...) { ... }

 that can be used also in functions that are expecting it:

 void worksOnA( .... ) { }
 void worksOnB( .... ) { }

 auto foo = Foo( ... )
 foo.a.worksOnA();
 foo.b.worksOnB();

 But I'm struggling in finding a good way to do it...
 Suggestions?

 Thanks!
 /Paolo
//https://dpaste.dzfl.pl/d59469c264b2 import std.algorithm : map, copy, equal; import std.range : iota; struct Foo { int[3] a; string[2] b; } ref T first(R : T[], T)(ref R x,){return x[0];} ref T second(R : T[], T)(ref R x){return x[1];} void worksOnA(R : int[N], size_t N)(ref R r) { iota(1, N+1) .map!(x => cast(int)x*2) .copy(r[]); } void worksOnB(string[] r) { } void main(){ auto foo = Foo(); foo.a.first = 1; foo.a.second = 2; assert(foo.a.first == 1); assert(foo.a.second == 2); foo.b.second = "test"; assert(foo.b.first == ""); assert(foo.b.second == "test"); foo.a.worksOnA(); assert(foo.a[].equal([2, 4, 6])); }
Jul 03 2017
parent reply Paolo Invernizzi <paolo.invernizzi gmail.com> writes:
On Monday, 3 July 2017 at 16:41:51 UTC, vit wrote:
 On Monday, 3 July 2017 at 13:53:45 UTC, Paolo Invernizzi wrote:
 [...]
//https://dpaste.dzfl.pl/d59469c264b2 import std.algorithm : map, copy, equal; import std.range : iota; struct Foo { int[3] a; string[2] b; } ref T first(R : T[], T)(ref R x,){return x[0];} ref T second(R : T[], T)(ref R x){return x[1];} void worksOnA(R : int[N], size_t N)(ref R r) { iota(1, N+1) .map!(x => cast(int)x*2) .copy(r[]); } void worksOnB(string[] r) { } void main(){ auto foo = Foo(); foo.a.first = 1; foo.a.second = 2; assert(foo.a.first == 1); assert(foo.a.second == 2); foo.b.second = "test"; assert(foo.b.first == ""); assert(foo.b.second == "test"); foo.a.worksOnA(); assert(foo.a[].equal([2, 4, 6])); }
Thanks for your solution, Vic! It's not exactly the same, as first and second should be struct with partial fields from Foo, of different types. /Paolo
Jul 03 2017
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
hOn 07/03/2017 10:13 AM, Paolo Invernizzi wrote:

 It's not exactly the same, as first and second should be struct with
 partial fields from Foo, of different types.
I had difficulty understanding the requirements. For example, it's not clear whether you want the literal "first" and "second" names. If you want to magically use part of a struct as a separate type, it's impossible in a strongly typed language like D. However, you have low-level options that allow you to lay data almost in any way you want. Obviously, if you have access to Foo's source and it's feasible to change it, you can do this: struct Foo { A a; B b; } Assuming that it's not possible, you can cast addresses of parts of the struct as addresses of other types. Compiles but not tested: struct Foo { int a_1; float a_2; string a_3; string b_1; double b_2; } struct A { int a_1; float a_2; string a_3; } struct B { string b_1; double b_2; } auto ref a(ref Foo foo) { return *cast(A*)&foo.a_1; } auto ref b(ref Foo foo) { return *cast(B*)&foo.b_1; } void worksOnA(ref A a) { } void worksOnB(ref B b) { } void main() { auto foo = Foo(); foo.a.worksOnA(); foo.b.worksOnB(); } Ali
Jul 03 2017
parent Paolo Invernizzi <paolo.invernizzi gmail.com> writes:
On Monday, 3 July 2017 at 17:30:51 UTC, Ali Çehreli wrote:
 hOn 07/03/2017 10:13 AM, Paolo Invernizzi wrote:

 [...]
struct with
 [...]
I had difficulty understanding the requirements. For example, it's not clear whether you want the literal "first" and "second" names. [...]
Thanks Ali, I'm doing something similar, with inout ref in the b function: I'll stick with that. Thanks again to all! /Paolo
Jul 03 2017