Issues - Superbelko/ohmygentool GitHub Wiki
This document describes potential issues in code that you might encounter and how to deal with them.
Suppose that we have following C++ code
void someFun()
{
MyStruct a(42);
//...
}
Now according to D Language specification page for structs the following equivalent is
void someFun()
{
MyStruct a = MyStruct(42);
//...
}
The same is true for classes.
void someFun()
{
float a = 42.F, b = random();
//...
}
This is not yet handled properly so it will look like
void someFun()
{
float a = 42fb = random();
//...
}
How to fix: just add the comma in between.
C++ allows calling constructor implicitly unless they are marked with explicit attribute
Vec2 getVector()
{
return 42, 42;
}
Or
Vec2 getVector()
{
return {42, 42};
}
Now depending on the case it might end up looking like
Vec2 getVector()
{
return Vec2((42, 42));
}
Notice the double parenthesis, get rid of the inner one set. Or
Vec2 getVector()
{
return Vec2(Vec2(42, 42));
}
Now there is extra construction takes the place, the fix is same, get rid of inner Vec2 and parenthesis set.
This looks trivial in C++
Vec2 getVector()
{
Vec2 vec;
// ... do some vec calculation ...
return vec;
}
But you can see something like this in generated code
Vec2 getVector()
{
Vec2 vec;
// ... do some vec calculation ...
return Vec2(vec);
}
Even though this code is perfectly valid it does change the meaning, so the proper fix is to get rid of copy construction
Vec2 getVector()
{
Vec2 vec;
// ... do some vec calculation ...
return vec;
}
This one is very rare, and I will try to fix this ASAP, but here is the example
template<typename T> class MyData
{
void setNew(T*);
T getVal();
// ...
}
Might end up looking like normal class
class MyData
{
void setNew(T*);
T getVal();
// ...
}
Notice that T parameter is gone, let's bring it back where it should be.
class MyData(T)
{
void setNew(T*);
T getVal();
// ...
}
Ok, this time something serious. Suppose that we want to select the type depending on some compile-time information, such as the size of the type.
template<int> struct typesel;
template<> struct typesel<4> { typedef int myint; };
template<> struct typesel<8> { typedef long long myint; };
// now use it to get properly sized type
typedef typesel<sizeof(OtherIntType)>::myint myint;
For those who are unfamiliar - this is the trick(or if you prefer - technique) called "Substitution Failure Is Not An Error", the compiler will try to select all variants and if they all failed issue an error, for that case there is generic version without implementation (line 1). Now there is 2 more real variants that does pretty obvious job. If we pass in any type with size of either 4 or 8 compiler will instantiate the relevant template.
But the thing is, D doesn't have (nor need) such tricks. However SFINAE leftovers will end up in the generated code...
struct typesel<1>;
struct typesel<1>;
alias myint = typesel<sizeof(OtherIntType)>::myint;
It has 3 problems:
- it has those leftovers for each variant
- it is not yet handled properly and the code pasted as is
- template variants information is gone and you have to look up the code yourself (in this simple case this isn't the problem because the code is generated for this particular situation)
The proper fix is to use CTFE or simply static if's
static if (OtherIntType.sizeof == 4)
alias myint = int;
else if (OtherIntType.sizeof == 8)
alias myint = long;
else static assert(0, "unknown type");
You can notice that this is totally different from original code