Pull to refresh

Comments 6

С++ SFINAE как-то по сравнению с этим ...., да лучше не сравнивать. По крайней мере тут шаманить не нужно. D всё же похож на первого кандидата на переход с C++, когда его комитет окончательно зарубит. Уж сильно похоже его развитие на показ своего Я и игры участников комитета.
UFO just landed and posted this here
Спасибо за серию статей…
Не поможете решить правильно проблему? Есть задача
  1. есть набор разных функций и делегатов, совпадающих по типам аргументов и результатов
  2. их нужно собрать в массив и применять какие-то однообразные действия(папример выполнить функию, получить результат,...)

То, что у меня получается выглядит не очень красиво. Мне не нравятся длинноты вида
X!(ReturnType!f, ParameterTypeTuple!f)(&f, «a») но я не могу найти как компактно описать одновременно тип возвращаемого значения и аргументов для функции.
И не очень нравится что раздельно описываются функции и делегаты. Теряется краткость.
Спасибо заранее
Думаю можно обойтись только делегатами и вынести в отдельную функцию создание класса.
Правка
import std.stdio;
import std.traits;

auto f(string s) {
    return s.length;
}

auto g(string s) {
    return 2*s.length;
}

struct S {
    auto getClosure() {
        return (string s) { return 3*s.length; };
    }
}

class X(R, A...) { // три точки значат, что можно это не один тип может быть, а кортеж типов
    R delegate(A) g;
    A a;

    this(R delegate(A) g, A a) {
        this.g = g;
        this.a = a;
    }

    R run() { return g(a); }
}

auto newX(F,Args...)( F fnc, Args args )
    if( isCallable!F && __traits(compiles, { fnc(args); }) )
    // F может быть даже объектом с методом opCall
    // с помощью __traits мы проверяем можем ли вызывать эту fnc с такими аргументами
{
    return new X!( ReturnType!F, ParameterTypeTuple!F ) // тип объекта всё равно нужно задавать
                 ( (Args a){ return fnc(a); }, args );
    // в любом случае создаём делегат
}

void main() {
    auto x = newX(&f, "a");
    auto y = newX(&g, "ab");
    auto s = S();
    auto d = s.getClosure();
    auto z = newX(d, "abc");
    auto Z = [x,y,z];
    foreach(t; Z) {
        writeln(t.run());
    }
}
Вариант функций создания
Вместо одной универсальной можно написать 2 специальные
auto newX(R,Args...)( R delegate(Args) fnc, Args args )
{ return new X!(R,Args)( fnc, args ); }

auto newX(R,Args...)( R function(Args) fnc, Args args )
{ return new X!(R,Args)( (Args a){ return fnc(a); }, args ); }


Можно озвучить более полную задачу? А то есть маленькое чувство, что Вы стреляете из пушки по воробьям.
Другой подход
import std.stdio;
import std.traits;

auto f(string s) {
    return s.length;
}

auto g(string s) {
    return 2*s.length;
}

struct S {
    auto getClosure() {
        return (string s) { return 3*s.length; };
    }
}

auto apply(F,Args...)( F fnc, Args args )
    if( isCallable!F && __traits(compiles,fnc(args)) )
{ return { return fnc(args); }; }

void main() {
    auto x = apply(&f, "a");
    auto y = apply(&g, "ab");
    auto s = S();
    auto d = s.getClosure();
    auto z = apply(d, "abc");
    auto Z = [x,y,z];
    foreach(t; Z) {
        writeln(t());
    }
}

Цель — написание кода для future's — это обьекты которые запускают асинхронно вызов и выполнение какой-либо функции и позволяют продолжить выполнение основной ветки кода плюс ожидание результатов future в нужный момент.

Удобно бывает собрать их в массив для того, что-бы ждать всех, собрать результат выполнения всех, и т.д. Собрать в массив можно только обьекты одного типа, поэтому обьекты future должны быть одного типа.

например
int pause(int x) {
   sleep(x);
   return 0;
}
int connect(int p) {
   auto c = connect_to_server('127.0.0.1', p);
   if (c.connected) {
      return 0;
   } else {
     return -1;
   }
}

auto tasks = map!run([future(pause, 10), future(connect, 80)]);
writeln("wait some time for results");
sleep(1);
auto result = map!waitResult(tasks);


Sign up to leave a comment.

Articles