Przeladowanie operatora szablon

0
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

class BladLamana:std::exception
{
public:
	virtual const char* what()
	{
		return "Blad Lamanej";
	}
};
template <class x,class y>class lamana
{
private:
	int lwierzcholkow;
public:
	struct wierzcholek
	{
		x wartoscx;
		y wartoscy;
		int w;
		wierzcholek():wartoscx(0),wartoscy(0)
		{
		}
		wierzcholek(x x,y y):wartoscx(x),wartoscy(y)
		{
		}
	};
	vector<wierzcholek> tmp;
	lamana(int liczba):lwierzcholkow(liczba)
	{
		for (int i=0;i<5;i++)
		{
			tmp.push_back(lamana<x,y>::wierzcholek(0,0));
		}
	}
	lamana& operator [] (int indeks);
	template<class x,class y> friend ostream& operator << (ostream&,lamana<x,y>&);
	template<class x,class y> friend istream& operator >> (istream&,lamana<x,y>&);
};
template <class x, class y> 
lamana<x, y>& lamana<x, y>:: operator [] (int indeks) 
{
	if (indeks<1 ||indeks>lwierzcholkow-1) throw BladLamana();
	return tmp[indeks];

}
template <class x,class y> ostream& operator << (ostream& os,lamana<x,y>& l)
{
	os<<l.lwierzcholkow<<endl;
	for (int i=0;i<l.lwierzcholkow;i++)
	{
	os<<"("<<l.tmp[i].wartoscx<<","<<l.tmp[i].wartoscy<<")";
	}
	return os;
}
template <class x,class y> istream& operator >> (istream& is,lamana<x,y>& w)
{
	return is;
}
int _tmain(int argc, _TCHAR* argv[])
{
	try
	{
		string name="lamana.txt";
	lamana<int,int> jeden(5);
	ofstream out(name.c_str(),ios::out);
	out<<jeden;
	for (int i=0;i<jeden.tmp.size();i++)
	{
		cout<<jeden.tmp[i].wartoscx<<jeden.tmp[i].wartoscy<<endl;
	}
	jeden[0].tmp[0].wartoscx=5;
	}
	catch(BladLamana& e)
	{
		cerr<<"Wystapil blad:"<<e.what()<<endl;
	}

	system ("pause");
	return 0;
}

Czy jest mozliwa modyfikacja operatora indeksowania w taki spsob aby otrzymac:
jeden[i]=(5,3);
Modyfikacja tmp[i].wierzcholekx oraz tmp[i].wierzcholeky???

0

Operator [] musi zwrócić obiekt proxy, który będzie miał przeładowany operatory = i ,. Wtedy będzie możliwe wykonanie cośtam[i] = 5, 3;.
Pamiętaj, żeby dostarczyć również zwykłą metodę, za pomocą której będzie można zrobić to samo (cośtam.SetCośtam(i, 5, 3);).

0

cośtam[i] = 5, 3;
domyślam się jak to będzie działać, ale to straszny hack jest, do tego zrozumiały tylko dla uber-mastahów.

nie lepiej po prostu

cośtam[i] = wierzcholek(5,6);

gdzie [] zwraca referencję, a wierzcholek() to konstruktor?

0

Będzie to faktycznie kompromis pomiędzy wygodą, a czytelnością i prostotą. Jeżeli miałbyś faktycznie polecić któreś z rozwiązań to właśnie to Azariena.

0

Wiec Azarien jak mam uzyc konstruktora wierzcholka kiedy jest on zagniezdzony w klasie lamana?
zwracanie referencji przez[] mialo by wygladac mniejwiecej tak?

lamana<x, y>& lamana<x, y>:: operator [] (int indeks) 
{
	if (indeks<1 ||indeks>lwierzcholkow-1) throw BladLamana();
	this->tmp[indeks];
	return *this;

}
0

Nie, masz zwrócić referencję do tego, co chcesz zmienić, czyli tmp[indeks].

0

Przy takim zapisie:

Error 3 error C2440: 'return' : cannot convert from 'lamana<x,y>::wierzcholek' to 'lamana<x,y> &'

0

Zmień typ, która zwraca ten operator. Od kiedy to operator [] zwraca samego siebie?

0

a dobra ok po zastosowaniu w main w/w zapisu pojawil sie blad:

Error 3 error C3861: 'wierzcholek': identifier not found
Takze ponawiam pytanie jak powinnien wygladac poprawny zapis
jeden[0]=wierzcholek(5,3);

1
template <class x,class y>
typename lamana<x,y>::wierzcholek& lamana<x,y>::operator [] (int indeks) {
   return tmp[indeks];
}

albo (C++11):

template <class x,class y>
auto lamana<x,y>::operator [] (int indeks) -> wierzcholek& {
  return tmp[indeks];
}
1

jeden[0] = lamana<int, int>::wierzcholek(5, 3).

0

ten wierzcholek to lepiej chyba wyjąć poza klasę lamana, bo tylko komplikuje składnię…

0

ok dziala. Fakt Rev zapis jest logiczny i dosc prosty moj blad. Jednak jednego nie wiem w jakim celu zostal tu uzyty typename. Oczywiscie sprawdzilem bez tego nie dziala...

1
Azarien napisał(a):

ten wierzcholek to lepiej chyba wyjąć poza klasę lamana, bo tylko komplikuje składnię…

Dokładnie. Do tego nie rozdzielać x i y jako osbne typy, bo i po co???

Ewentualnie można sobie zrobić typedef'a dla konkretnych typów:

typedef lamana<double, double> lamana_d;

lamana_d jeden(1);
jeden[0] = lamana_d::wierzcholek(5,3);
0
Zsanoj napisał(a):

Jednak jednego nie wiem w jakim celu zostal tu uzyty typename

Jeżeli typ B zawiera się w typie A, to normalnie żeby odwołać się do B piszemy A::B.
Ale jeśli A jest szablonem, to nie można zrobić A<T>::B, tylko trzeba typename A<T>::B.

Prawdopodobnie bez tego byłaby jakaś niejednoznaczność składni gdzie indziej, inaczej by tego nie wprowadzali.

0

Wsumie google nie boli;].kompilator nie wie, ze lamana::wierzcholek& jest typem, mogloby to byc cos innego, np zmienna dla tego zostalo tutaj uzyte typename.
Ah pieknie dziekuje za poswiecenie mi czasu.

0

Jeszcze żeby typename można było ZAWSZE pisać, np.

typename int i;

to nie byłoby problemu.
A tak - raz trzeba, raz nie wolno, i sprowadza się do tego że się pisze w ciemno i patrzy czy kompilator przełknie.

0

Mógłbyś rozwinąć myśl? Kiedy nie wolno? Chodzi ci o ewentualne konflikty nazw???

0

Jesli moglbym prosic jeszcze o wyjasnienie jednej sprawy. Chodzi mi o operator strumieniowy >>
Chodzi mi ignorowanie znakow ( oraz , o ile dobrze pamietam w C byl specjalny znacznik ktory wczytywal takie znaki w proznie a jak to rozwiazc jesli chodzi o strumien tak aby wartosci byly poprawne.

template <class x,class y> istream& operator >> (istream& is,lamana<x,y>& w)
{
	is >>w.lwierzcholkow;
	for (int i=0;i<w.lwierzcholkow;i++)
	{
	is >>w.tmp[i].wartoscx>>w.tmp[i].wartoscy;
	}
	return is;
}

Kombinuje z is.ingore(256,',');
juz wczytuje pierwsza liczbe, jednak to praca na chybil trafil bez znajomosci danej funckji.

0

Ok doszlem do nieco patologicznej metody ale dziala ;p

template <class x,class y> istream& operator >> (istream& is,lamana<x,y>& w)
{
	is >>w.lwierzcholkow;
	for (int i=0;i<w.lwierzcholkow;i++)
	{
	is.ignore(2,'(');
	is >>w.tmp[i].wartoscx;
	is.ignore(2,',');
	is >>w.tmp[i].wartoscy;
	is.ignore(2,')');
	}
	return is;
}
 
0

z tego co sie dowiedzialem manipulator ws pomija biale znaki jak spacja tabulator itd. Sprawdzilem w takiej postaci nie zadziala.

0
Azarien napisał(a):

nie lepiej po prostu

cośtam[i] = wierzcholek(5,6);

gdzie [] zwraca referencję, a wierzcholek() to konstruktor?

Z C++11 powinno się dać zrobić coś takiego:

costam[i] = {5,6}

(Z zastowaniem proxy)
http://pl.wikipedia.org/wiki/C%2B%2B11#Listy_inicjuj.C4.85ce

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