Thread overview
Define methods using templates
Dec 30, 2014
Claude
Dec 30, 2014
Daniel Kozák
Dec 30, 2014
Claude
Dec 30, 2014
Ali Çehreli
Jan 08, 2015
Claude
December 30, 2014
Hello, I'm trying to use templates to define several methods (property setters) within a class to avoid some code duplication.
Here is an attempt:

class Camera
{
private:
    Vector4 m_pos;
    float m_fov, m_ratio, m_near, m_far;
    bool m_matrixCalculated;

public:
    void SetProperty(Tin, alias Field)(ref Tin param) @property pure @safe
    {
        Field = param;
        m_matrixCalculated = false;
    }

    alias pos   = SetProperty!(float[], m_pos);
    alias pos   = SetProperty!(Vector4, m_pos);
    alias ratio = SetProperty!(float,   m_ratio);
    alias near  = SetProperty!(float,   m_near);
    alias far   = SetProperty!(float,   m_far);
}

I get this kind of compilation error:
Error: template instance SetProperty!(float[], m_pos) cannot use local 'm_pos' as parameter to non-global template SetProperty(Tin, alias Field)(ref Tin param)

I don't understand why that error occurs.

And I cannot find any elegant solutions (even with mixin's) to declare a template and then instantiate it in a single line to define the methods I want.

Does any of you have an idea?

Thanks
December 30, 2014
On 12/30/14 8:17 AM, Claude wrote:
> Hello, I'm trying to use templates to define several methods (property
> setters) within a class to avoid some code duplication.
> Here is an attempt:
>
> class Camera
> {
> private:
>      Vector4 m_pos;
>      float m_fov, m_ratio, m_near, m_far;
>      bool m_matrixCalculated;
>
> public:
>      void SetProperty(Tin, alias Field)(ref Tin param) @property pure @safe
>      {
>          Field = param;
>          m_matrixCalculated = false;
>      }
>
>      alias pos   = SetProperty!(float[], m_pos);
>      alias pos   = SetProperty!(Vector4, m_pos);
>      alias ratio = SetProperty!(float,   m_ratio);
>      alias near  = SetProperty!(float,   m_near);
>      alias far   = SetProperty!(float,   m_far);
> }
>
> I get this kind of compilation error:
> Error: template instance SetProperty!(float[], m_pos) cannot use local
> 'm_pos' as parameter to non-global template SetProperty(Tin, alias
> Field)(ref Tin param)
>
> I don't understand why that error occurs.

I think it has to do with the fact that when you are defining the aliases, m_pos for example, is an *instance* member so requires an instance to get an alias.

What you are probably better off doing is:

void SetProperty(Tin, string Field)(ref Tin param) @property pure @safe
{
   mixin(Field ~ " = param;");
   m_matrixCalculated = false;
}

alias pos = SetProperty!(float[], "m_pos");

I would also put some strict template constraints on the Field string too, because one abuse SetProperty pretty easily there.

-Steve
December 30, 2014
On 12/30/14 8:48 AM, Steven Schveighoffer wrote:

> I think it has to do with the fact that when you are defining the
> aliases, m_pos for example, is an *instance* member so requires an
> instance to get an alias.
>
> What you are probably better off doing is:
>
> void SetProperty(Tin, string Field)(ref Tin param) @property pure @safe
> {
>     mixin(Field ~ " = param;");
>     m_matrixCalculated = false;
> }
>
> alias pos = SetProperty!(float[], "m_pos");
>
> I would also put some strict template constraints on the Field string
> too, because one abuse SetProperty pretty easily there.

A possibly more elegant solution, use opDispatch:

void opDispatch(string Field, Tin)(ref Tin param) @property pure @safe if(Field == "pos" || Field == "ratio" || ...)
{
   mixin("m_" ~ Field ~ " = param;");
   m_matrixCalculated = false;
}

Not sure if opDispatch works as a @property this way...

-Steve
December 30, 2014
V Tue, 30 Dec 2014 13:17:08 +0000
Claude via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com>
napsáno:

> Hello, I'm trying to use templates to define several methods (property setters) within a class to avoid some code duplication. Here is an attempt:
> 
> class Camera
> {
> private:
>      Vector4 m_pos;
>      float m_fov, m_ratio, m_near, m_far;
>      bool m_matrixCalculated;
> 
> public:
>      void SetProperty(Tin, alias Field)(ref Tin param) @property
> pure @safe
>      {
>          Field = param;
>          m_matrixCalculated = false;
>      }
> 
>      alias pos   = SetProperty!(float[], m_pos);
>      alias pos   = SetProperty!(Vector4, m_pos);
>      alias ratio = SetProperty!(float,   m_ratio);
>      alias near  = SetProperty!(float,   m_near);
>      alias far   = SetProperty!(float,   m_far);
> }
> 
> I get this kind of compilation error:
> Error: template instance SetProperty!(float[], m_pos) cannot use
> local 'm_pos' as parameter to non-global template
> SetProperty(Tin, alias Field)(ref Tin param)
> 
> I don't understand why that error occurs.
> 
> And I cannot find any elegant solutions (even with mixin's) to declare a template and then instantiate it in a single line to define the methods I want.
> 
> Does any of you have an idea?

> 
> Thanks

class Camera
{
private:
    int m_pos;
    float m_fov, m_ratio, m_near, m_far;
    bool m_matrixCalculated;

public:
    mixin template opAssign(alias Field) {
        void opAssign(Tin)(auto ref Tin param) @property pure @safe
        {
            Field = param;
            m_matrixCalculated = false;
        }
    }

    mixin opAssign!(m_pos)   pos;
    mixin opAssign!(m_fov)   fov;
    mixin opAssign!(m_ratio) ratio;
    mixin opAssign!(m_near)  near;
    mixin opAssign!(m_far)   far;

}

void main() {

    Camera cam = new Camera();

    cam.fov = 1.0;
    stdin.readln;
}


December 30, 2014
Thanks Steven and Daniel for your explanations.

>     mixin template opAssign(alias Field) {
>         void opAssign(Tin)(auto ref Tin param) @property pure @safe
>         {
>             Field = param;
>             m_matrixCalculated = false;
>         }
>     }
>
>     mixin opAssign!(m_pos)   pos;

I tested both the "string mixin" and "opAssign" implementations, and they work like a charm.
I would have never thought of using both @property and "opAssign", but it looks like a secure way of doing it for the compilation fails nicely if I type a wrong field in.

src/camera.d(58): Error: undefined identifier m_os, did you mean variable m_pos?
December 30, 2014
On 12/30/2014 05:17 AM, Claude wrote:

> use templates to define several methods (property
> setters) within a class to avoid some code duplication.

I just saw this post, which is essentially the same question as Basile Burg's. I hope that a college (in France?) is teaching D and that this is a homework assignment. Cool stuff! :)

Ali

January 08, 2015
> I just saw this post, which is essentially the same question as Basile Burg's. I hope that a college (in France?) is teaching D and that this is a homework assignment. Cool stuff! :)

Maybe using templates to create properties is a bit overkill in this example. But I could not solve what I thought would be a very simple and straightforward "template use-case" (initially I'm an embedded RT system C/asm developer).

I'm doing this for a personal project of a 3D engine. As I know little about C++/Java or other OO language, I thought I would do it directly in D, which seems very promising to me (but unfortunately not taught in France as far as I know).