LINUX.ORG.RU

шаблон для цепочки операций с массивом, или как имплементировать ленивость?

 , ,


2

3

Пускай есть некоторый шаблонный класс для представления массива. И есть члены шаблонного класса, например A, B, C, D, .. совпадающие по количеству элементов. В шаблоне реализованы арифметические операции +=, -=, *=, /= для операций с парами (массив, массив) и (массив,скаляр) внутри они представляют из себя обычные циклы (в общем случае распараллеленные), а так же оператор присваивания и конструктор копирования.

Вопрос, как прегрузить обычные бинарные операции так, что бы избежать выделения памяти под промежуточные члены класса и как спрятать всю цепочку вычислений внутрь одного цикла?

Например, A = C+B*(D/2.0f). Если считать влоб, то получается 4 цикла и 3 выделения памяти, в то же время, если как-то реализовать ленивость, то достаточно собрать цепочку вычислений элемента и посчитать всё внутри одного цикла. Как такое правильно сделать?

★★★★★

Последнее исправление: thunar (всего исправлений: 2)

велкам ту сипласплас. Еще скажи спасибо, если компилятор конструкторы копирования лишние повыкидывает.

Waterlaz ★★★★★
()
Последнее исправление: Waterlaz (всего исправлений: 1)

Не проще ли обычный builder pattern сделать? И нагляднее и проще.

Слабо себе представляю как можно сделать ленивость поверх стандартных операторов. Ведь кто-то должен запустить выполнение.

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Слабо себе представляю как можно сделать ленивость поверх стандартных операторов. Ведь кто-то должен запустить выполнение.

Влоб. Можно сделать класс Expression. Операторы перегрузить так, чтобы они принимали в качестве аргументов как требуемые классы, так и выражения, но возвращали всегда выражение. И определить преобразование из Expression в требуемы классы. Соответственно, выполнение будет запускаться в момент преобразования из типа Expression.

Waterlaz ★★★★★
()
Ответ на: комментарий от RazrFalcon

Со стандартными операторами есть дефолтная ленивость.

Например,

if(func1() && func2())

func2 не будет выполнено, если func1 вернёт false

с перегруженными операторами не прокатит, но фичу удобно использовать для воспроизведения ленивости в определённых ситуациях

next_time ★★★★★
()
Последнее исправление: next_time (всего исправлений: 1)
Ответ на: комментарий от RazrFalcon

стандартом совершенно точно определено, искать по ключевым словам short-circuit evaluation

next_time ★★★★★
()
Ответ на: комментарий от Pinkbyte

Вот и весь ваш lazy evaluation

template  <class T>
class X
{
Func* f = nullptr; //вместо Func либо typedef указателя на функцию
//либо std::function, либо ещё какая обёртка, на свой вкус
T t;
public:
T& get()
{
   return f ? t, f(t);
}
T& set(const T& _t, Func* _f)
{
   t = _t, f = _f;
   return t;
}
operator T&() 
{
  return get();
}

};

short-circuit позволяет условно тоже самое, но только в пределах одного выражения

next_time ★★★★★
()
Ответ на: комментарий от Pinkbyte

Что-то такое встречал. Сейчас гугл подсказывает только то, что не для всех операторов задан чёткий порядок. Это не UB, как бы, но порядок выполнения действительно может быть произвольный:

https://stackoverflow.com/a/7925696/1153097

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

http://en.cppreference.com/w/cpp/language/eval_order

http://en.cppreference.com/w/cpp/language/operator_precedence

«Every overloaded operator obeys the sequencing rules of the built-in operator it overloads when called using operator notation.»

«Operators that have the same precedence are bound to their arguments in the direction of their associativity.»

из этого следует, что в выражении

std::cout<<"s"<<1<<func1()<<func2()<<func(3);

Порядок вычислений функций func1, func2, func3 неопределён, однако, как раз, операторы «<<» выполнятся в порядке слева направо.

next_time ★★★★★
()
Ответ на: комментарий от RazrFalcon

Ну это уже чисто инкрементов/декрементов проблемы. Лично я считаю, что их следует избегать, кроме простейших выражений. Просто потому, что плохо читаются и при модификации выражения грозят внезапным «ой».

next_time ★★★★★
()
Ответ на: комментарий от next_time

Не совсем. Такое поведение гарантируется стандартом:

void func1(int &i) { assert(i == 1); i++; }
void func2(int &i) { assert(i == 2); i++; }

int i = 1;
std::cout << func1(i) << func2(i);

?

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

вообще не скомпилируется: применение оператора к ф-ии, возвр. void

но если, она будет возвращать ссылку на &int и написать return i, как вы, очевидно, хотели, то нет, не гарантируется

next_time ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.