Wskaźniki wskazujące na operacje arytmetyczne a nie tylko na zmienne i tablice ?

0

Cześć.
wiem co to są wskaźniki, referencje. Ale czy
jest ich odpowiednik który wskazuje na jakąś operacje arytmetyczną np:

 int liczba=4,liczba2=1;
int#wynik=liczba+liczba2;
cout<<wynik<<endl;//dostaje 5
//teraz modyfikuję zmienną liczba na 1
liczba=1;
// i dostaję wynik=2
cout<<wynik<<endl;

tu tylko pokazuje jakby to miało działać ale wiadomo że kompilator da inny wynik. Skoro da się na zmienną to trzemu by się miało nie dać na sumę 2 zmiennych. Nie wielka różnica.

0

@kamil kowalski:

Właśnie wynalazłeś wskaźniki na funkcje (wskaźniki funkcyjne)

https://cpp0x.pl/kursy/Kurs-C++/Poziom-X/Wskaznik-na-funkcje/249

edit: odpowiedź jest na poziomie C, w C++ są różne cudeńka z metaprogramowania, ani nie mam konkretnego czegoś na myśli, ani nie umiał bym wytłumaczyć

0

Spróbuj zrobić ten przykład co napisałem w oparciu o wskaźniki na funkcje.

3
ZrobieDobrze napisał(a):

@kamil kowalski:

Właśnie wynalazłeś wskaźniki na funkcje (wskaźniki funkcyjne)

A nie bardziej obiekt? C++ nie umiem więc napiszę w Scali (w maksymalnie imperatywnym stylu, nie róbcie tego w domu)

class AddCalculation(var liczba: Int = 0, var liczba2: Int= 0) {
  def wynik() = liczba + liczba
}

val c = new AddCalculation()
c.liczba = 4
c.liczba2 = 1
printlin(c.wynik())//dostaje 5

//teraz modyfikuję zmienną liczba na 1
c.liczba = 1;
printlin(c.wynik())
// i dostaję wynik=2
1
kamil kowalski napisał(a):

Spróbuj zrobić ten przykład co napisałem w oparciu o wskaźniki na funkcje.

int add(int x, int y)
{
  
}

a dalej jak w przytoczonym artykule (to nie boli)

wynik = addPointer(liczba1, liczba2)
4

Możesz po prostu leniwie ewaluować wartość wynik dopiero tam, gdzie jest potrzebny.

#include <iostream>

class Sum {
public:
    Sum(int& l1, int& l2): l1_(l1), l2_(l2) {}

    int operator*() { return l1_ + l2_; }

private:
    int& l1_;
    int& l2_;
};

int main() {
    int l1=4, l2=1;
    Sum s(l1, l2);
    std::cout << *s << std::endl;
    l1=1;
    std::cout << *s << std::endl;
}
0

Z tego co piszecie wygląda to jak zmodyfikowana moja wersja na

 int liczba=4,liczba2=1;
int wynik=liczba+liczba2;
cout<<wynik<<endl;//dostaje 5
//teraz modyfikuję zmienną liczba na 1
liczba=1;
wynik=liczba+liczba2;/////////////////////////tu dokładam tylko
// i dostaję wynik=2
cout<<wynik<<endl;

edit
tu ma być nie wynik =2 tylko 5

 int liczba=4,liczba2=1;
int wynik=liczba+liczba2;
cout<<wynik<<endl;//dostaje 5
//teraz modyfikuję zmienną liczba na 1
liczba=1;
wynik=liczba+liczba2;/////////////////////////tu dokładam tylko
// i dostaję wynik=5///////////tu jeszcze zmieniam
cout<<wynik<<endl;

2

Generalnie programowanie obiektowe przenosi dawny wskaźnik funkcyjny na inny poziom, samodzielnego, pełnego obiektu
najpopularniejszy chyba to wzorzec Strategia

Złap różnice, czy się różni od przykładu @Spearhead

abstract class NumericStrategy {
public:
performSum (int a, int b) = 0;
};

....

class AddStrategy : NumericStrategy {
...
}

...

NumericStrategu * computation = new AddStrategy();

2
#include <iostream>
#include <functional>
#include <unordered_map>
using namespace std;

template<typename T,char op> class operation
{
	private:
	T &a,&b;
	T calc(T a,T b)const
	{
		static unordered_map<char,function<T(T,T)>> tb
		{
			{'+',[](T a,T b) { return a+b; }},
			{'-',[](T a,T b) { return a-b; }},
			{'*',[](T a,T b) { return a*b; }},
			{'/',[](T a,T b) { return a/b; }},
		};
		return tb[op](a,b);
	}
	T calc()const { return calc(a,b); }
	public:
	operation(T &a,T &b):a(a),b(b) {}
	explicit operator T()const { return calc(a,b); }
	friend ostream &operator<<(ostream &s,const operation &opr) { return s<<opr.calc();  }
};

int main()
{
 	int liczba=4,liczba2=1;
	operation<int,'+'> wynik(liczba,liczba2);
	cout<<wynik<<endl;//dostaje 5
	//teraz modyfikuję zmienną liczba na 1
	liczba=1;
	cout<<wynik<<endl; // i dostaję wynik=2
	return 0;
}
1

tu jest polimorfizm i dziedziczenie. — kamil kowalski 2 minuty temu

Tak, zupa składa się z wody, soli, makaronu, zródła białka, warzyw.
Zauważyłeś zarazem słusznie, a i zupełnie nieproduktywnie.

Dokladnie, używa się (na przykład) polimorfizmu - do użycia na wyższym poziomie abstrakcji.
ktos zauwazył "o kurcze, widzicie, wszyscy często używamy tego podobnie", i zostało to nazwane wzorcem Strategii

0

To co pokazujesz to programowanie deklaratywne. Jedyny język jaki mi przychodzi do głowy, gdzie to jest możliwe to QML.

Chociaż efekt jest do odtworzenia też w językach imperatywnych (patrz: React.js)

0

Jedyny język z jakim mi się kojarzy to VHDL kiedy tworzy się układy kombinacyjne. Tyle że tam kolejność poza procesami nie ma znaczenia w części do tego przeznaczonej.

0

Jak już oddalamy się bardzo daleko od C/C++ to Groovy closures (ooo! bardzo dobrze pasuje graficznie do oczekiwania) , lambdy Javy i C# co mi się w zmęczone popoludnie nasuwa ... jest KUPĘ możliwości przygotowanie funkcjonalności czynnościowej (tzn nie danych) aby wykonać później,
https://groovy-lang.org/closures.html

W kazdym profesjonalnie używanym jezyku. Bo jest po prostu potrzebne

0

Czyli raczej nie ma czegoś takiego o czym piszę. W zasadzie wystarczyło by stworzyć jakiś program który wykrywa ten "nowy wskaźnik" z # i za każdym razem jak się zmieni zmienna która może mieć wpływ na wynik to po tej operacji wykonuje się przypisanie do zmiennej ponownie. Czyli ten kod po tej konwersji przez ten program zamienia nowy wskaźnik z # na zmienną która jest aktualizowana w przypadku który napisałem wcześniej.

1
kamil kowalski napisał(a):

i za każdym razem jak się zmieni zmienna która może mieć wpływ na wynik to po tej operacji wykonuje się przypisanie do zmiennej ponownie.

To cos podobnego do listenera, ale a) prostej zmiennej nie da się nasłuchiwać b) nie w C, wątpliwe w C++

kamil kowalski napisał(a):

Czyli raczej nie ma czegoś takiego o czym piszę. W zasadzie wystarczyło by stworzyć jakiś program który wykrywa ten "nowy wskaźnik" z # i za każdym razem jak się zmieni zmienna która może mieć wpływ na wynik to po tej operacji wykonuje się przypisanie do zmiennej ponownie. Czyli ten kod po tej konwersji przez ten program zamienia nowy wskaźnik z # na zmienną która jest aktualizowana w przypadku który napisałem wcześniej.

A jakis PRAKTYCZNY temat cie meczy ? Bo to tak zaczyna pachnieć - na początku wydawało sie że zainteresowanie czysto teoretryczne

2

Aha, jeszcze jedno.
Zmienne mające "bogate życie wewnętrzne" to są właściwości, property.
Najładniej zrealizowane w C#. Tam w pełni jest do wyobrażenia klasa z trzema takimi właściwościami itd

No i w hipotetycznym jezyku interpretowanym (zlepek z kilku)

let expr = '{zmienna1} + {zmienna2}'

let znienna1 = 2

let zmiena2 =3

let wynik = eval(expr)
zmienna 2 =7

let wynik = eval(expr)
0

Wystarczył by program który pobiera plik tekstowy a następnie wypluwa już zmodyfikowany. — kamil kowalski 2022-11-28 19:42

Nagle zmieniasz płaszczyznę na plik. To wysyła cały wątek dyskusji do kosza.
Powiedz, czy sam dla siebie masz jasne, co chcesz uzyskać ?

2

Takie coś pasuje?

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

class operation;

class item
{
	private:
	typedef void (operation::*Informer)(item*);
	int value;
	vector<operation*> objects;
	Informer informer;
	public:
	item(int value=int{}):value(value) {}
	item(const item &it):value(it.value) { change(); }
	item &operator=(int value) { this->value=value; change(); return *this; }
	void add(operation *object) { objects.push_back(object); }
	void remove(operation *object) { objects.erase(std::remove(begin(objects),end(objects),object),end(objects)); }
	friend ostream &operator<<(ostream &s,const item &it) { return s<<it.value;  }
	friend istream &operator>>(istream &s,item &it) { return s>>it.value;  }
	operator int()const { return value; }
	void set(int value) { this->value=value; change(); }
	int get()const { return value; }
	void change();
};

class operation
{
	private:
	bool changed;
	item &a,&b;
	int value;
	public:
	operation(item &a,item &b):changed(true),a(a),b(b) 
	{
		a.add(this);
		b.add(this);
	}
	~operation()
	{
		a.remove(this);
		b.remove(this);
	}
	void changing(item *sender)
	{
		if(sender==&a) cout<<"first operand changed"<<endl; //do wywalenia
		else if(sender==&b) cout<<"second operand changed"<<endl; //do wywalenia
		else cout<<"OTHER operand changed, WTF?"<<endl; //do wywalenia
		changed=true;
	}
	int recalc()
	{
		if(changed)
		{
			cout<<"Recalc now"<<endl; //do wywalenia
			value=a.get()+b.get();			
		}
		return value;
	}
	operator int() { return recalc(); }
	friend ostream &operator<<(ostream &s,operation &opr) { return s<<opr.recalc();  }
};

void item::change() { for(operation *op:objects) op->changing(this); }

int main()
{
 	item liczba=4,liczba2=1;
	operation wynik(liczba,liczba2);
	cout<<"Expect 5: "<<wynik<<endl;
	liczba=1;
	cout<<"Expect 2: "<<wynik<<endl; // i dostaję wynik=2
	liczba2=7;
	cout<<"Expect 8: "<<wynik<<endl; // i dostaję wynik=8
	liczba2=100;
	liczba=700;
	liczba=70;
	liczba2=10;
	cout<<"Expect 80: "<<wynik<<endl; // i dostaję wynik=80
	return 0;
}```
0
kamil kowalski napisał(a):

Czyli raczej nie ma czegoś takiego o czym piszę. W zasadzie wystarczyło by stworzyć jakiś program który wykrywa ten "nowy wskaźnik" z # i za każdym razem jak się zmieni zmienna która może mieć wpływ na wynik to po tej operacji wykonuje się przypisanie do zmiennej ponownie. Czyli ten kod po tej konwersji przez ten program zamienia nowy wskaźnik z # na zmienną która jest aktualizowana w przypadku który napisałem wcześniej.

Brzmi jak sygnały i sloty lub observer pattern.
Ergo popaprz na Qt, albo boost::signals2 lub podobne rozwiązania.
Albo doczytaj jak wygląd wzorzec obserwator.

0

A tak w skrócie: Co potrzebuje OP?
Co nie pasuje w propozycji @_13th_Dragon?
Może ktoś się tu zafiksował na "genialne własne rozwiązanie" i nie jest otwarty na alternatywę?

A takie magiczne sztuczki jak to robi Qt "Meta-Object Compiler (moc.exe)" , czy łatwo zrobić własne rozwiązanie i rozszerzenie języka o jeszcze więcej magii ?

1 użytkowników online, w tym zalogowanych: 0, gości: 1