Zadanie na szablonach funkcji

Zadanie na szablonach funkcji
Z0
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 5 lat
  • Postów:47
0

Witam mam problem z dokończeniem zadania z szablonów funkcji. Problem polega na tym że nie wiem jak dokończyć 2 pierwsze funkcje i je potem wywołać oraz poprawić 3(drukującą) tak by nie wyrzucała błędów. Tu jest opis zadania:

Stwórz trzy szablony funkcji:
• Funkcja filtrująca:

Kopiuj
template <typename T, typename FunType> 
vector<T> filter(const vector<T>& v, FunType p);

która pobiera wektor v i funkcję (predykat) p pobierającą daną typu, jakiego są elementy wektora a zwracającą bool. Funkcja filter zwraca wektor tego samego typu co v i zawierający tylko te elementy wektora v, dla których predykat p zwraca true.

• Funkcja transformująca i filtrująca:

Kopiuj
template <typename T, typename FunType1, typename FunType2>
 vector<T> transfilt(vector<T>& v, FunType1 t, FunType2 p);

która pobiera wektor, funkcję transformującą t i predykat p. Wektor v (przesłany przez referencję) jest modyfikowany w ten sposób, że każdy jego element zastąpiony jest wynikiem działania na ten element funkcji transformującej. Funkcja transfilt zwraca wektor tego samego typu co v zawierający tylko te elementy przetransformowanego wektora v, dla których predykat p zwraca true.

• Funkcja drukująca:

Kopiuj
template <typename T>
void printVec(const vector<T>& v) {

która pobiera wektor i drukuje w jednym wierszu, ujętym w nawiasy kwadratowe, jego elementy oddzielone znakami odstępu.

W wywołaniach funkcji filter i transfilt argumenty funkcyjne powinny być lambdami zdefiniowanymi bezpośrednio na liście argumentów.

Jeśli w następującym programie:

Kopiuj
#include <cmath> 
#include <iostream> 
#include <functional> 
#include <vector>

using std::vector; 
using std::function;

template <typename T, typename FunType> vector<T> filter(const vector<T>& v, FunType p) {
// ...
}

template <typename T, typename FunType1, typename FunType2> 
vector<T> transfilt(vector<T>& v, FunType1 t, FunType2 p) { // ... }

template <typename T> 
void printVec(const vector<T>& v) { // ... }

int main() { 
vector<int> v{1, -3, 4, -2, 6, -8, 5}; 
printVec(v); 
vector<int> r = filter(v, /* lambda_1 */);
printVec(r); 
vector<int> s = filter(v, /* lambda_2 */); 
printVec(s);
vector<double> w{1.5, -3.1, 4.0, -2.0, 6.3}; 
printVec(w); double mn = -0.5, mx = 0.5; 
vector<double> d = transfilt(w, /* lambda_3*/, /* lambda_4 */); 
printVec(w); 
printVec(d);
} 

lambdy są
• lambda_1 — zwraca true dla liczb parzystych;
• lambda_2 — zwraca true dla liczb dodatnich;
• lambda_3 — zwraca sinus argumentu (std::sin z nagłówka cmath);
• lambda_4 — zwraca true dla liczb z zkresu [mn,mx],

to powinien on wypisać:
[ 1 -3 4 -2 6 -8 5 ]
[ 4 -2 6 -8 ]
[ 1 4 6 5 ]
[ 1.5 -3.1 4 -2 6.3 ]
[ 0.997495 -0.0415807 -0.756802 -0.909297 0.0168139 ]
[ -0.0415807 0.0168139 ]
Uwaga: nie używaj żadnych dodatkowych funkcji z biblioteki standardowej.

A tutaj jest to co ja już napisałem:

Kopiuj

#include <cmath>
#include <iostream>
#include <functional>
#include <vector>

using std::vector; 
using std::function;

using namespace::std;

template <typename T, typename FunType>
vector<T> filter(const vector<T>& v, FunType p) {
v lambda1(v a)
	for (int i = 0, v.size, i++) {
			if (v[i] % 2 = 0)
				cout << v[i];
		}

	
		for (int i = 0, v.size, i++) {
				if (v[i] >= 0)
				cout << v[i];
		}
}

template <typename T, typename FunType1, typename FunType2>
vector<T> transfilt(vector<T>& v, FunType1 t, FunType2 p) {
	for (int i = 0, v.size, i++) { 
		cout << sin(v[i]) 
	}


for (int i = 0, v.size, i++) if (v[i] <= mx && v[i] >= mn)
{
	cout << v[i];
}
}

template <typename T>
void printVec(const vector<T>& v) {			
	int i = 0;
	while (v.size() > 0)
{
		cout << v[i];
		cout << " ";
		i += 1;
}
	}

int main() {
	vector<int> v{ 1, -3, 4, -2, 6, -8, 5 }; 
	printVec(v); 
	vector<int> r = filter(v, lambda1);
	printVec(r); 
	vector<int> s = filter(v, p2);
	printVec(s);

	vector<double> w{ 1.5, -3.1, 4.0, -2.0, 6.3 };
	printVec(w); 
	double mn = -0.5, mx = 0.5; 
	vector<double> d =
		transfilt(w, , );
	printVec(w);
	printVec(d);
}

Zdaję sobie sprawę że one nie są dobrze napisane, ale dlatego właśnie pytam się jak to powinno być, bo sam długo już próbuję to zrobić i mi nie wychodzi.

edytowany 1x, ostatnio: zax00000
lion137
Sformatuj to porządnie.
Z0
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 5 lat
  • Postów:47
0

Czy takie sformatowanie jest wystarczające by to odczytać?

tajny_agent
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad rok
  • Postów:1340
1
zax00000 napisał(a):
Kopiuj
template <typename T, typename FunType>
vector<T> filter(const vector<T>& v, FunType p) {
v lambda1(v a)
	for (int i = 0, v.size, i++) {
			if (v[i] % 2 = 0)
				cout << v[i];
		}

	
		for (int i = 0, v.size, i++) {
				if (v[i] >= 0)
				cout << v[i];
		}
}

Lambda powinna być przekazana jako parametr funkcji filter i powinna być wywoływana dla każdego elementu osobno.

Kopiuj
template<typename ElemType, typename FuncType>
vector<ElemType> filter(vector<ElemType> const& data, FuncType&& func)
{
  vector<ElemType> filtered;
  for (auto it = data.cbegin(); it != data.cend(); ++it) {   // dla każdego elementu...
    if (func(*it))   // jeśli func zwróci dla danego elementu true...
      filtered.push_back(*it);  // dodaj element do wektora wynikowego
  }
  return filtered;
}

// a wywołujesz to np. tak
vector<int> values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
auto results = filter(values, [](int elem){ return elem % 2 == 0; });  // przepuści tylko liczby parzyste

"I love C++. It's the best language in the world right now for me to write the code that i need and want to write"
~ Herb Sutter
Z0
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 5 lat
  • Postów:47
0

Dzięki za wyjaśnienie, czy mógłbyś napisać tylko jeszcze jak poprawić funkcję drukującą, bo ona mi wyświetla ale rzuca przy tym błędami po wykonaniu.

tajny_agent
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad rok
  • Postów:1340
0
zax00000 napisał(a):
Kopiuj
template <typename T>
void printVec(const vector<T>& v) {			
	int i = 0;
	while (v.size() > 0)
{
		cout << v[i];
		cout << " ";
		i += 1;
}
	}

Masz tutaj nieskończoną pętle dla każdego wektora, który nie jest pusty. Nie usuwasz żadnych elementów z wektora, więc v.size() > 0 jest zawsze prawdziwe i co za tym idzie wychodzisz poza zakres.

Wystarczy użyć standardowego range-for:

Kopiuj
template<typename T>
void printVec(vector<T> const& v)
{
  cout << "[ ";
  for (auto elem : v) {
    cout << elem << ' ';
  }
  cout << "]\n";
}

"I love C++. It's the best language in the world right now for me to write the code that i need and want to write"
~ Herb Sutter
Z0
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 5 lat
  • Postów:47
0

Mam jeszcze pytanie odnośnie funkcji transfilt. Jeżeli mam polecenie "że każdy jego element zastąpiony jest wynikiem działania na ten element funkcji transformującej" to skąd mam wziąźć aktualny element vectora v, chodzi mi o to że w for jest metoda na wzięcie początku i końca vectora v, ale nie ma iteratora, a przecież muszę na każdym z jego elementów wykonać działanie, czy jest jakaś możliwość jego wzięcia, ja na razie znalazłem coś takiego jak _Make_iterator(), ale niezbyt mi on działa

Kopiuj
template <typename T, typename FunType1, typename FunType2>
vector<T> transfilt(vector<T>& v, FunType1 t, FunType2 p) {
	vector<T> filtered;
	for (auto it = v.cbegin(); it != v.cend(); ++it) {
		if (p(*it))
			filtered.push_back(*it);
	}
	return filtered;
}
}

Napisałem do tego od razu wywołanie i wydaje mi się że powinno tak wyglądać

Kopiuj

vector<double> d =
		transfilt(w, [](double elem1) { return sin(elem1); }, [mn, mx](double elem2) { return elem2 > mn && elem2 <= mx; });

Z0
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 5 lat
  • Postów:47
0

Jeżeli użyłem iteratora w ten sposób to jak wywołać na nim parametry funkcji

Kopiuj

template <typename T, typename FunType1, typename FunType2>
vector<T> transfilt(vector<T>& v, FunType1 t, FunType2 p) {
	vector<T> filtered;
	for (auto it = v.cbegin(); it != v.cend(); ++it) {
		if (v::iterator(t, p)(*it))
			filtered.push_back(*it);
	}
	return filtered;
}

tajny_agent
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad rok
  • Postów:1340
0

Iteratory mają semantykę wskaźnika. Inkrementacja przechodzi do następnego elementu, dereferencja wyłuskuje wartość, etc.
Zaletą pisania funkcji opartych na iteratorach jest to, że możesz jej użyć zarówno dla std::vector jak i std::map, std::unordered_set, czy nawet jakiejś własnej klasy.
W przypadku wektora kod

Kopiuj
for (auto it = vec.begin(); it != vec.end(); ++it) {
  process_element(*it);
}

jest tożsamy z kodem

Kopiuj
for (auto i = 0u; i < vec.size(); ++i) {
  process_element(vec[i]);
}

Jeśli wiesz, że funkcja będzie działać tylko i wyłącznie na wektorze to nic nie stoi na przeszkodzie, żeby zamiast iteratorów użyć po prostu indeksów.


"I love C++. It's the best language in the world right now for me to write the code that i need and want to write"
~ Herb Sutter
Z0
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 5 lat
  • Postów:47
0

Rozumiem o co chodzi w for, tylko jak należy to napisać żeby działało z funkcją transformującą i predykatem p. Nie wiem w jaki sposób wywołać 2 parametry na 1 vectorze.

Już nieważne poradziłem sobie z tym w ten sposób:

Kopiuj

template <typename T, typename FunType1, typename FunType2>
vector<T> transfilt(vector<T>& v, FunType1 t, FunType2 p) {
	vector<T> process_element;
	for (auto i = 0; i < v.size(); ++i) {
		v[i] = t(v[i]);
		if (p(v[i]))
		process_element.push_back(v[i]);
	}
	return process_element;
}

edytowany 1x, ostatnio: zax00000

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.