Thread overview
New to D and mimicking C++ : how to implement std::integral_constant<>?
Nov 07, 2016
Picaud Vincent
Nov 07, 2016
Jerry
Nov 07, 2016
Picaud Vincent
Nov 07, 2016
Picaud Vincent
Nov 07, 2016
Jerry
Nov 07, 2016
Picaud Vincent
Nov 07, 2016
Picaud Vincent
Nov 07, 2016
Picaud Vincent
Nov 08, 2016
Basile B.
Nov 08, 2016
Picaud Vincent
November 07, 2016
Hi all,

I have ~15y of C++ and now I want to test D, because it seems really intersting and "cleaner" than C++.

As an exercice I m trying to implement something equivalent to the C++ std::integral_constant<T,T value> in D.

In D:

struct IntegralConstant(T, T VALUE) {
 ...
}

But I do not know how to write a compile-time type check. I tried

template isIntegralConstant(ANY)
{
    enum bool isIntegralConstant=__traits(identifier,ANY)=="IntegralConstant";
}

But when using it with ANY=long type, I get a compile-time error:

"argument long has no identifier"

A workaround that worked is:

struct IntegralConstantTag {}

struct IntegralConstant(T, T VALUE) {
  private IntegralConstantTag selfTag_;
  alias selfTag_ this;
}

template isIntegralConstant(ANY)
{
    enum bool isIntegralConstant=is(ANY : IntegralConstantTag);
}

But now I'm sticked by a compiler issue when I want to introduce 2 "alias this" to allow implicit conversion:

struct IntegralConstant(T, T VALUE) {
  private IntegralConstantTag selfTag_;
  alias selfTag_ this;
  T value_=VALUE;
  alias value_ this;
}

Compiler error message is "integralConstant.d:16:3: error: there can be only one alias this".


I would be very graceful for any help/advice that explains the right way to implement C++ std::integral_constant<T,T value> in the D language.

Vincent

November 07, 2016
On Monday, 7 November 2016 at 18:42:37 UTC, Picaud Vincent wrote:
> template isIntegralConstant(ANY)
> {
>     enum bool isIntegralConstant=__traits(identifier,ANY)=="IntegralConstant";
> }

A bit more elegant way of doing that would be:

enum isIntegralConstant(T) = is(T : IntegralConstant!U, U...);


> I would be very graceful for any help/advice that explains the right way to implement C++ std::integral_constant<T,T value> in the D language.
>
> Vincent

Now the question is, do you really need IntegralConstant? I've never used it in C++ so I don't really know any of the use cases for it. But generally in D if you need something to be a compile time constant value you can just use "enum". It can be any type as well, so long as it can be evaluated at compile time.

enum long someConstant = 1 << 32;


November 07, 2016
On Monday, 7 November 2016 at 18:59:24 UTC, Jerry wrote:
> On Monday, 7 November 2016 at 18:42:37 UTC, Picaud Vincent wrote:
>> template isIntegralConstant(ANY)
>> {
>>     enum bool isIntegralConstant=__traits(identifier,ANY)=="IntegralConstant";
>> }
>
> A bit more elegant way of doing that would be:
>
> enum isIntegralConstant(T) = is(T : IntegralConstant!U, U...);
>
>
>> I would be very graceful for any help/advice that explains the right way to implement C++ std::integral_constant<T,T value> in the D language.
>>
>> Vincent
>
> Now the question is, do you really need IntegralConstant? I've never used it in C++ so I don't really know any of the use cases for it. But generally in D if you need something to be a compile time constant value you can just use "enum". It can be any type as well, so long as it can be evaluated at compile time.
>
> enum long someConstant = 1 << 32;

Hi Jerry,

Thank you so much for your quick answer! I tried your suggestion and it works.

My main interest is numerical computations. I have some C++ libs using meta-programming and I want to see how I can translate some parts in D. The goal is to check: productivity & code readability & performance. I will try to implement 2 toy examples:

1/ A basic example of strided dense vector structure dealing with the dynamic/static size in an uniform way. In D I thing this can be done with something like this (not tried yet to compile it, but that is the idea to mimick my C++ implementation)

struct Vector(T,SIZE,STRIDE) if( (is(SIZE==size_t)||isIntegralConstant!SIZE) ...)
{
  alias T ElementType;

  private SIZE size_;
  private STRIDE stride_;

  ...

  auto required_capacity() { return size_*stride_; } // return a size_t or a IntegralConst

  static if ( isIntegralConstant!(typeof(required_capacity()) )
{
}
else
{
}

}
November 07, 2016
On Monday, 7 November 2016 at 21:23:37 UTC, Picaud Vincent wrote:
> On Monday, 7 November 2016 at 18:59:24 UTC, Jerry wrote:
>> On Monday, 7 November 2016 at 18:42:37 UTC, Picaud Vincent wrote:
>>> template isIntegralConstant(ANY)
>>> {
>>>     enum bool isIntegralConstant=__traits(identifier,ANY)=="IntegralConstant";
>>> }
>>
>> A bit more elegant way of doing that would be:
>>
>> enum isIntegralConstant(T) = is(T : IntegralConstant!U, U...);
>>
>>
>>> I would be very graceful for any help/advice that explains the right way to implement C++ std::integral_constant<T,T value> in the D language.
>>>
>>> Vincent
>>
>> Now the question is, do you really need IntegralConstant? I've never used it in C++ so I don't really know any of the use cases for it. But generally in D if you need something to be a compile time constant value you can just use "enum". It can be any type as well, so long as it can be evaluated at compile time.
>>
>> enum long someConstant = 1 << 32;
>
> Hi Jerry,
>
> Thank you so much for your quick answer! I tried your suggestion and it works.
>
> My main interest is numerical computations. I have some C++ libs using meta-programming and I want to see how I can translate some parts in D. The goal is to check: productivity & code readability & performance. I will try to implement 2 toy examples:
>
> 1/ A basic example of strided dense vector structure dealing with the dynamic/static size in an uniform way. In D I thing this can be done with something like this (not tried yet to compile it, but that is the idea to mimick my C++ implementation)
>
> struct Vector(T,SIZE,STRIDE) if( (is(SIZE==size_t)||isIntegralConstant!SIZE) ...)
> {
>   alias T ElementType;
>
>   private SIZE size_;
>   private STRIDE stride_;
>
>   ...
>
>   auto required_capacity() { return size_*stride_; } // return a size_t or a IntegralConst
>
>   static if ( isIntegralConstant!(typeof(required_capacity()) )
> {
> }
> else
> {
> }
>
> }

Premature post send by error sorry.... Well something like:

   static if ( isIntegralConstant!(typeof(required_capacity()) )
     ElementType[required_capacity()] data_;
   else
     ElementType[] data_;
}

For that, at least in C++, I need integral_constant<> type with compile-time arithmetic and smooth integration with "usual" size_t/ptrdiff_t types.

2/ I also would like to test some implementations concerning automatic differentiation.
I have my own C++ libs, inspired, but ~20% faster than Adept:
http://www.met.reading.ac.uk/clouds/adept/
and I would like to know how I can do that in D

Well... That is the idea... I hope I will get some results and I will be happy to share if it is something interesting.

Vincent

November 07, 2016
On Monday, 7 November 2016 at 21:37:50 UTC, Picaud Vincent wrote:
>>   static if ( isIntegralConstant!(typeof(required_capacity()) )
>> {
>> }
>> else
>> {
>> }
>>
>> }
>
> Premature post send by error sorry.... Well something like:
>
>    static if ( isIntegralConstant!(typeof(required_capacity()) )
>      ElementType[required_capacity()] data_;
>    else
>      ElementType[] data_;
> }
>
> For that, at least in C++, I need integral_constant<> type with compile-time arithmetic and smooth integration with "usual" size_t/ptrdiff_t types.
>
> 2/ I also would like to test some implementations concerning automatic differentiation.
> I have my own C++ libs, inspired, but ~20% faster than Adept:
> http://www.met.reading.ac.uk/clouds/adept/
> and I would like to know how I can do that in D
>
> Well... That is the idea... I hope I will get some results and I will be happy to share if it is something interesting.
>
> Vincent

Ah I get what you mean, you can do that without using a special type.

    struct Vector(T, Args...) if(Args.length == 1)
    {
        static if(is(Args[0] == size_t))
        {
            size_t size;
        }
        else static if(Args[0] != 0) // would error if it's a type that's not size_t
        {
            enum size = Args[0];
        }
        else
        {
            static assert(0);
        }
    }

    Vector!(int, 10) a;
    Vector!(int, size_t) b; // both work with IntegralConstant

could use __traits(compiles) to see if it's not a type, for that second static if. Which would probably be better, so if you pass a float or something, it won't give a weird error.
November 07, 2016
On Monday, 7 November 2016 at 22:18:56 UTC, Jerry wrote:
> On Monday, 7 November 2016 at 21:37:50 UTC, Picaud Vincent wrote:
>>>   static if ( isIntegralConstant!(typeof(required_capacity()) )
>>> {
>>> }
>>> else
>>> {
>>> }
>>>
>>> }
>>
>> Premature post send by error sorry.... Well something like:
>>
>>    static if ( isIntegralConstant!(typeof(required_capacity()) )
>>      ElementType[required_capacity()] data_;
>>    else
>>      ElementType[] data_;
>> }
>>
>> For that, at least in C++, I need integral_constant<> type with compile-time arithmetic and smooth integration with "usual" size_t/ptrdiff_t types.
>>
>> 2/ I also would like to test some implementations concerning automatic differentiation.
>> I have my own C++ libs, inspired, but ~20% faster than Adept:
>> http://www.met.reading.ac.uk/clouds/adept/
>> and I would like to know how I can do that in D
>>
>> Well... That is the idea... I hope I will get some results and I will be happy to share if it is something interesting.
>>
>> Vincent
>
> Ah I get what you mean, you can do that without using a special type.
>
>     struct Vector(T, Args...) if(Args.length == 1)
>     {
>         static if(is(Args[0] == size_t))
>         {
>             size_t size;
>         }
>         else static if(Args[0] != 0) // would error if it's a type that's not size_t
>         {
>             enum size = Args[0];
>         }
>         else
>         {
>             static assert(0);
>         }
>     }
>
>     Vector!(int, 10) a;
>     Vector!(int, size_t) b; // both work with IntegralConstant
>
> could use __traits(compiles) to see if it's not a type, for that second static if. Which would probably be better, so if you pass a float or something, it won't give a weird error.

Thank you again Jerry!

For sure my way of thinking is twisted by my C++ habits! :-/

The positive point is that D seems to offer much shorter solutions (this is my hope).

However I still need some investigations and/or some guidance:

-> not sure that it is ok for me as I really want to track "static constants" all the
   way long.
   That is the reason why I introduced the IntegralConstant type
   (with operator overloading, work in progress)

For instance, the code:

 enum int a=1,b=2;
 auto c = a+b;

 pragma(msg,typeof(c));   // prints "int"
 static assert(c==3);     // compilation fails: "variable c cannot be read at compile time"

To implement my vector structs I need:

1/ a way to detect compile-time constant vs "dynamic" values
2/ to perform and to propagate compile-time constants across "arithmetic" computations.
   For instance to compute the required capacity to store vector data, I need something
like

auto capacity = max(0,(size_-1)*stride_);

and this expression must make sense for both "dynamic" values and compile-time constant.

In one case I expect
   typeof(capacity) -> int,
in the other
   typeof(capacity) -> IntegralConst

November 07, 2016
typo...
auto capacity = max(0,(size_-1)*stride_+1);

November 07, 2016
On Monday, 7 November 2016 at 23:07:27 UTC, Picaud Vincent wrote:
> typo...
> auto capacity = max(0,(size_-1)*stride_+1);

To be more correct I have something like:

alias IntergralConstant!(int,0) Zero_c;
alias IntergralConstant!(int,1) One_c;

auto capacity = max(Zero_c,(size_-One_c)*stride_+One_c);

with "smooth" implicit conversion IntegralConstant -> int for cases where size_ or stride_ are "int" and not both IntegralConstant types.

November 08, 2016
On Monday, 7 November 2016 at 23:03:32 UTC, Picaud Vincent wrote:
>  I need:
>
> 1/ a way to detect compile-time constant vs "dynamic" values

/**
 * Indicates if something is a value known at compile time.
 *
 * Params:
 *      V = The value to test.
 *      T = Optional, the expected value type.
 */
template isCompileTimeValue(alias V, T...)
if (T.length == 0 || (T.length == 1 && is(T[0])))
{
    enum isKnown = is(typeof((){enum v = V;}));
    static if (!T.length)
        enum isCompileTimeValue = isKnown;
    else
        enum isCompileTimeValue = isKnown && is(typeof(V) == T[0]);
}
///
unittest
{
    string a;
    enum b = "0";
    enum c = 0;
    static assert(!isCompileTimeValue!a);
    static assert(isCompileTimeValue!b);
    static assert(isCompileTimeValue!c);
    static assert(isCompileTimeValue!(b,string));
    static assert(isCompileTimeValue!(c,int));
    static assert(!isCompileTimeValue!(c,char));
    static assert(!isCompileTimeValue!(char));
}


November 08, 2016
Hi Basile,
Thank you for your code, it allowed me to grasp a little bit more about how to do things in D.
Vincent