Thread overview | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
September 06, 2019 C++ vs D: Default param values and struct to array casting | ||||
---|---|---|---|---|
| ||||
C++ allows the for following: struct Demo { float a, b, c, d; Demo() { a = b = c = d = 0.0f; } Demo(float _a, float _b, float _c, float _d) { a = _a; b = _b; c = _c; d = _d; } float operator[] (size_t i) const { return (&a)[i]; } //[3] float& operator[] (size_t i) { return (&a)[i]; } //[4] } void fun(float col[3]) { // do fun stuff } void moreFun(const Demo& d = Demo(0.1f, 0.3f, 7.5f, 1.5f)) // [1] { // you guessed it... more fun stuff } int main(int argv, const char** argc) { Demo inst = Demo(0.1f, 0.3f, 7.5f, 1.5f); fun((float*)&inst); // [2] moreFun(); return 0; } I'm seeking some pointers on how to define these in D so that I can instantiate them in D while still linking to the associated C++ library or object file for the implementation. The main points of contention are at [1] and [2] because I have no idea how to accomplish these. I assume that I can accomplish [3] and [4] with opIndex() and opIndexAssign(), however I'm not understanding the slicing of the memory address at the first member variable. I know that by indexing the memory address at the member variable we are able treat the struct as an array but i do not understand how to implement it in D. I read the documentation at https://dlang.org/spec/cpp_interface.html and https://dlang.org/articles/cpptod.html but it was not clear "to me" how to overcome these issues. Andrew |
September 06, 2019 Re: C++ vs D: Default param values and struct to array casting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Edwards | On Friday, 6 September 2019 at 09:14:31 UTC, Andrew Edwards wrote:
> C++ allows the for following:
>
> struct Demo
> {
> float a, b, c, d;
> Demo() { a = b = c = d = 0.0f; }
> Demo(float _a, float _b, float _c, float _d) {
> a = _a;
> b = _b;
> c = _c;
> d = _d;
> }
> float operator[] (size_t i) const { return (&a)[i]; } //[3]
> float& operator[] (size_t i) { return (&a)[i]; } //[4]
> }
This is my thought on how to accomplish op overloading:
struct Test
{
float a, b, c, d;
float opIndex(size_t i)
in(i >= 0 && i <= 3)
{
final switch(i)
{
case 0: return a;
case 1: return b;
case 2: return c;
case 3: return b;
}
}
void opIndexAssign(float val, size_t i)
in(i >= 0 && i <= 3)
{
final switch(i)
{
case 0: a = val; break;
case 1: b = val; break;
case 2: c = val; break;
case 3: d = val; break;
}
}
}
Please advise if I've gone off the beaten path. It seems overkill for the two lines of code C++ requires so any suggestion is greatly appreciated.
|
September 06, 2019 Re: C++ vs D: Default param values and struct to array casting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Edwards | On Friday, 6 September 2019 at 09:14:31 UTC, Andrew Edwards wrote: > C++ allows the for following: > > struct Demo > { > float a, b, c, d; > Demo() { a = b = c = d = 0.0f; } > Demo(float _a, float _b, float _c, float _d) { > a = _a; > b = _b; > c = _c; > d = _d; > } > float operator[] (size_t i) const { return (&a)[i]; } //[3] "(&a)[i]" is undefined behavior in C++. You cannot index into struct members like that. Of course it may work in certain cases, but UB is UB. Don't do it! I found a more detailed explanation for you: https://stackoverflow.com/questions/40590216/is-it-legal-to-index-into-a-struct -Johan |
September 06, 2019 Re: C++ vs D: Default param values and struct to array casting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johan Engelen | On Friday, 6 September 2019 at 09:49:33 UTC, Johan Engelen wrote:
> On Friday, 6 September 2019 at 09:14:31 UTC, Andrew Edwards wrote:
>> C++ allows the for following:
>>
>> struct Demo
>> {
>> float a, b, c, d;
>> Demo() { a = b = c = d = 0.0f; }
>> Demo(float _a, float _b, float _c, float _d) {
>> a = _a;
>> b = _b;
>> c = _c;
>> d = _d;
>> }
>> float operator[] (size_t i) const { return (&a)[i]; } //[3]
>
> "(&a)[i]" is undefined behavior in C++. You cannot index into struct members like that. Of course it may work in certain cases, but UB is UB. Don't do it!
>
> I found a more detailed explanation for you: https://stackoverflow.com/questions/40590216/is-it-legal-to-index-into-a-struct
>
> -Johan
Thanks for the clarification and link. This is a example taken from a popular library I’m trying to port to D. I’m not trying to do it in C++ myself, just to understand how to interface to the code so that I can get a reference example compiled in D.
Andrew
|
September 06, 2019 Re: C++ vs D: Default param values and struct to array casting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Edwards | On Friday, 6 September 2019 at 09:14:31 UTC, Andrew Edwards wrote: > C++ allows the for following: > > struct Demo > { > float a, b, c, d; > Demo() { a = b = c = d = 0.0f; } > Demo(float _a, float _b, float _c, float _d) { > a = _a; > b = _b; > c = _c; > d = _d; > } > float operator[] (size_t i) const { return (&a)[i]; } //[3] > float& operator[] (size_t i) { return (&a)[i]; } //[4] > } > https://dlang.org/spec/simd.html also probably u can do https://run.dlang.io/is/WMQE93 |
September 06, 2019 Re: C++ vs D: Default param values and struct to array casting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Edwards | On Friday, 6 September 2019 at 09:28:57 UTC, Andrew Edwards wrote:
> This is my thought on how to accomplish op overloading:
>
> struct Test
> {
> float a, b, c, d;
> float opIndex(size_t i)
> in(i >= 0 && i <= 3)
> {
> final switch(i)
> {
> case 0: return a;
> case 1: return b;
> case 2: return c;
> case 3: return b;
> }
> }
>
> void opIndexAssign(float val, size_t i)
> in(i >= 0 && i <= 3)
> {
> final switch(i)
> {
> case 0: a = val; break;
> case 1: b = val; break;
> case 2: c = val; break;
> case 3: d = val; break;
> }
> }
> }
>
> Please advise if I've gone off the beaten path. It seems overkill for the two lines of code C++ requires so any suggestion is greatly appreciated.
You can use `static foreach` to eliminate the repetition in the switch statements. For example:
float opIndex(size_t i)
in (i < typeof(this).tupleof.length)
{
final switch (i) {
static foreach (fid, field; typeof(this).tupleof) {
case fid: return field;
}
}
}
|
September 06, 2019 Re: C++ vs D: Default param values and struct to array casting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Edwards | On 09/06/2019 02:14 AM, Andrew Edwards wrote: > I'm seeking some pointers on how to define these in D Here is my attempt: struct Demo { // NOTE: The types and number of elements can be templatized and mixed-in like // mixin (makeMembers!T(N)); float a = 0; float b = 0; float c = 0; float d = 0; // Then these checks would be unnecessary static assert(a.sizeof == b.sizeof); static assert(b.sizeof == c.sizeof); static assert(c.sizeof == d.sizeof); // And this would be equal to N enum length = this.sizeof / a.sizeof; this(const(float)[] init...) { asSlice[0..init.length] = init; } auto asSlice() inout { // WARNING: As UNDEFINED BEHAVIOR as in the C++ code! return (&a)[0..length]; } ref asArray(size_t n = length)() inout { // WARNING: As UNDEFINED BEHAVIOR as in the C++ code! return *cast(float[n]*)(&a); } ref inout(float) opIndex(size_t i) inout { // [3] [4] return asSlice[i]; } } unittest { import std.algorithm; static assert (Demo.length == 4); void enforceMemberWiseEquality(Demo d, const(float)[] values) { switch (values.length) { case 4: assert(d.d == values[3]); goto case; case 3: assert(d.c == values[2]); goto case; case 2: assert(d.b == values[1]); goto case; case 1: assert(d.a == values[0]); goto default; default: break; } } const init = [1.0f, 2.0f, 3.0f, 4.0f]; // Test constructing with different number of expressions foreach (length; 0..init.length) { auto testInit = init[0..length]; const d = Demo(testInit); enforceMemberWiseEquality(d, testInit); assert(d.asArray[0..length].equal(testInit)); assert(d.asSlice[0..length].equal(testInit));} } extern (C++) void fun(float* col) { // do fun stuff } extern (C++) void moreFun(ref const(Demo) d) { // [1] // you guessed it... more fun stuff } // This is needed because operations inside asSlice are not allowed // at compile time. (That's why I could not make this variable 'static'. immutable(Demo) moreFun_default; shared static this() { moreFun_default = Demo(0.1f, 0.3f, 7.5f, 1.5f); } extern (C++) void moreFun() { // [1] // We need this function because D does not allow rvalue references. // Here, we're passing an lvalue. moreFun(moreFun_default); } int main() { Demo inst = Demo(0.1f, 0.3f, 7.5f, 1.5f); fun(inst.asSlice.ptr); // [2] moreFun(); return 0; } Ali |
September 06, 2019 Re: C++ vs D: Default param values and struct to array casting | ||||
---|---|---|---|---|
| ||||
Posted in reply to a11e99z | On Friday, 6 September 2019 at 11:35:59 UTC, a11e99z wrote: > > https://dlang.org/spec/simd.html This didn't work two well because I wont be able to access the members by name as C++ library expects. Will consider during refactoring. > also probably u can do https://run.dlang.io/is/WMQE93 Ended up using this since it provides for named access and solves the overloading requirement. Thanks, Andrew |
September 06, 2019 Re: C++ vs D: Default param values and struct to array casting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Edwards | On Friday, 6 September 2019 at 18:39:47 UTC, Andrew Edwards wrote: >> also probably u can do https://run.dlang.io/is/WMQE93 > > Ended up using this since it provides for named access and solves the overloading requirement. > > Thanks, > Andrew You can also use std.typecons.Tuple for this, since it provides both named and indexed access: https://run.dlang.io/is/bB21sX |
September 07, 2019 Re: C++ vs D: Default param values and struct to array casting | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Friday, 6 September 2019 at 18:31:29 UTC, Ali Çehreli wrote:
> On 09/06/2019 02:14 AM, Andrew Edwards wrote:
>
> > I'm seeking some pointers on how to define these in D
>
> Here is my attempt:
>
Ali, this is awesome. It solves all 4 problems in on shot. I definitely don't intend on using the undefined aspect in the future but it is welcomed at the moment.
Much appreciated.
Andrew
|
Copyright © 1999-2021 by the D Language Foundation