Zadanie na szablonach funkcji

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:

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:

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:

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:

#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:


#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.

0

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

1
zax00000 napisał(a):
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.

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
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.

0
zax00000 napisał(a):
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:

template<typename T>
void printVec(vector<T> const& v)
{
  cout << "[ ";
  for (auto elem : v) {
    cout << elem << ' ';
  }
  cout << "]\n";
}
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

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ć


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

0

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


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;
}

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

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

jest tożsamy z kodem

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.

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:


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;
}

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