June 14, 2012
I'm trying to constrain a struct template based on a parameter that's supposed be a function with a certain signature. Difficult to explain, easier just to show the problem:

module pseudorange;

struct PseudoInputRange(T, alias advance)
    //The next line doesn't compile
    //if (is(typeof(advance(T.init)) == void))
{
private:
    T m_front;
    T m_end;

public:
    this(T begin, T end) pure nothrow
    {
        m_front = begin;
        m_end = end;
    }

    @property immutable(T) front() const pure nothrow
    {
        return m_front;
    }

    void popFront() pure nothrow
    {
        advance(m_front);
    }

    @property bool empty() const pure nothrow
    {
        return m_front == m_end;
    }
}

//...

module main;

import std.stdio;
import std.range;
import pseudorange;

int main(string[] argv)
{
    alias PseudoInputRange!(int, (ref int x) {++x;}) MyRange;
    static assert(isInputRange!MyRange);

    foreach (x; MyRange(1, 11))
    {
        writeln(x);
    }
    stdin.readln();
    return 0;
}
June 14, 2012
On 06/14/2012 02:57 PM, Tommi wrote:
> I'm trying to constrain a struct template based on a parameter that's
> supposed be a function with a certain signature. Difficult to explain,
> easier just to show the problem:
>
> module pseudorange;
>
> struct PseudoInputRange(T, alias advance)
> //The next line doesn't compile
> //if (is(typeof(advance(T.init)) == void))
> ...
> alias PseudoInputRange!(int, (ref int x) {++x;}) MyRange;
> static assert(isInputRange!MyRange);
>

'T.init' is not an lvalue and can therefore not be passed by ref.
You can fix the problem with the fewest keystrokes like this:
if (is(typeof(advance([T.init][0])) == void))