std::set_difference z własną klasą

0

Witajcie,

co muszę zrobić, aby std::set_difference działał mi z własną klasą? Co muszę do takiej klasy dorzucić?
Dorzuciłem już const_iterator'y i iterator'y (begin() i end()). Czego jeszcze brakuje? Jakichś operatorów?

MojaKlasa roznica;
MojaKlasa rezultat;
MojaKlasa drugiRezultat;

std::set_difference( rezultat.begin(), rezultat.end(),
 drugiRezultat.begin(), drugiRezultat.end(),
 std::inserter( roznica, roznica.begin() ) );

Kiedy działam na std::vector to kod powyżej działa. Jeżeli działam na MojaKlasa to wywala:

Error 1 error C2893: Failed to specialize function template 'std::insert_iterator<_Container> std::inserter(_Container &,_Container::iterator)'
Error 2 error C2780: '_OutTy *std::set_difference(_InIt1,_InIt1,_InIt2,_InIt2,_OutTy (&)[_OutSize],_Pr)' : expects 6 arguments - 5 provided
Error 3 error C2780: '_OutIt std::set_difference(_InIt1,_InIt1,_InIt2,_InIt2,_OutIt,_Pr)' : expects 6 arguments - 5 provided

Proszę o pomoc.

0

Failed to specialize function template 'std::insert_iterator<_Container> std::inserter(_Container &,_Container::iterator)'

Błąd pierwszy mówi o problemie z std::inserter, a nie std::set_difference. Na tym się skup.

Masz też podaną od razu deklarację tej funkcji. Widać że drugi parametr jest typu _Container::iterator. Masz taki typ wewnątrz swojej klasy?

0
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <list>

class MojaKlasa
{
	std::vector< int > moje;
	
public:
	std::vector< int >::iterator begin()
	{
		moje.begin();
	}

	std::vector< int >::iterator end()
	{
		moje.end();
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	MojaKlasa roznica;
	MojaKlasa rezultat;
	MojaKlasa drugiRezultat;
 
	std::set_difference( rezultat.begin(), rezultat.end(),
	drugiRezultat.begin(), drugiRezultat.end(),
	std::inserter( roznica, roznica.begin() ) );
	return 0;
}

Tak to wygląda.. Czym jest owy _Container?

0

Czym jest owy _Container?
Twoją klasą.

Na pewno musisz dodać w klasie publicznie typedef o nazwie iterator. Skoro używasz wewnętrznie vectora, to możesz użyć jego iteratora.

class MojaKlasa
{
  public:
        typedef std::vector< int >::iterator iterator;

na tym się zapewne nie skończy.

EDIT: tu masz opis std::inserter() wraz z wymaganiami http://www.cplusplus.com/reference/iterator/inserter/
a tutaj co dokładnie powinien zawierać "container": http://en.cppreference.com/w/cpp/concept/Container
(nie wszystko musi być wymagane przez inserter())

0
class MojaKlasa
{
	std::vector< int > moje;
	
public:
	typedef std::vector< int >::iterator iterator;

	iterator begin()
	{
		moje.begin();
	}

	iterator end()
	{
		moje.end();
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	MojaKlasa roznica;
	MojaKlasa rezultat;
	MojaKlasa drugiRezultat;
 
	std::set_difference( rezultat.begin(), rezultat.end(),
	drugiRezultat.begin(), drugiRezultat.end(),
	std::inserter( roznica, roznica.begin() ) );
	return 0;
}

Jak to jest, że dodałem tego typedef'a i rzuca już całkowicie innymi błędami? Przecież poprzednio było tak samo... typedef jest jak using... zwykły alias. Mogę prosić o wytłumaczenie jak to kompilator zinterpretował? Nigdy jeszcze nie opakowywałem kontenera, dlatego może trywialne pytania, ale dla mnie dość ciężkie... Teraz mam błędy:

Error 1 error C2039: 'const_reference' : is not a member of 'MojaKlasa' c:\program files (x86)\microsoft visual studio 10.0\vc\include\iterator
Error 2 error C2146: syntax error : missing ';' before identifier 'const_reference' c:\program files (x86)\microsoft visual studio 10.0\vc\include\iterator
Error 3 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int c:\program files (x86)\microsoft visual studio 10.0\vc\include\iterator
Error 4 error C2602: 'std::insert_iterator<_Container>::const_reference' is not a member of a base class of 'std::insert_iterator<_Container>' c:\program files (x86)\microsoft visual studio 10.0\vc\include\iterator
Error 5 error C2868: 'std::insert_iterator<_Container>::const_reference' : illegal syntax for using-declaration; expected qualified-name c:\program files (x86)\microsoft visual studio 10.0\vc\include\iterator
Error 6 error C2039: 'value_type' : is not a member of 'MojaKlasa' c:\program files (x86)\microsoft visual studio 10.0\vc\include\iterator
Error 7 error C2182: '_Val' : illegal use of type 'void' c:\program files (x86)\microsoft visual studio 10.0\vc\include\iterator
Error 8 error C2182: '_Val' : illegal use of type 'void' c:\program files (x86)\microsoft visual studio 10.0\vc\include\iterator

EDIT
OK już coraz bliżej:

#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <list>

class MojaKlasa
{
	std::vector< int > moje;
	
public:
	typedef std::vector< int >::iterator iterator;
	typedef std::vector< int >::const_reference const_reference;
	typedef std::vector< int >::value_type value_type;

	iterator begin()
	{
		moje.begin();
	}

	iterator end()
	{
		moje.end();
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	MojaKlasa roznica;
	MojaKlasa rezultat;
	MojaKlasa drugiRezultat;
 
	std::set_difference( rezultat.begin(), rezultat.end(),
	drugiRezultat.begin(), drugiRezultat.end(),
	std::inserter( roznica, roznica.begin() ) );
	return 0;
}

Error 1 error C2039: 'insert' : is not a member of 'MojaKlasa' c:\program files (x86)\microsoft visual studio 10.0\vc\include\iterator

Teraz tylko jak zrobić tego insert'a... Jeszcze raz proszę o wytłumaczenie mi skąd kompilator wie, że te wszystkie typedef'y tyczą się tych rzeczy... W C# implementuje się IEnumerable i jest z górki, a tutaj nic nie jest implementowane, a kompilator wie, że ta klasa ma się tak zachowywać...

0

W skrócie: funkcje STL są szablonowe i zakładają, że typ, na którym mają operować, udostępnia pewien interfejs. To jest w zasadzie analogiczne do implementacji IEnumerable.

Spójrz na deklarację inserter:

template<typename Container>
  insert_iterator<Container> inserter(Container& x, typename Container::iterator it);

Metoda zakłada, że typ na jakim ma operować, udostępnia podtyp iterator – po to właśnie potrzebny jest typedef.

insert() musisz również zaimplementować (a w zasadzie owrappować ten z twojego kontenera). Raczej nie musisz wrappować wszystkich, powinno wystarczyć iterator insert (const_iterator position, const value_type& val).

A tutaj, jak widzisz, zakładany jest w interfejsie const_iterator; jego też powinieneś zadeklarować przez typedef.

0

C# implementuje się IEnumerable i jest z górki, a tutaj nic nie jest implementowane

w C++ jest podobnie: klasa ma zawierać to i to i to i to, ale nie ma pojęcia „interfejsu”, przez co jest trudniej się dowiedzieć co trzeba zaimplementować...

a kompilator wie, że ta klasa ma się tak zachowywać...
Kompilator „nic nie wie”. Skoro inserter() używa gdzieś wewnętrznie metody insert() na podanym obiekcie, to siłą rzeczy klasa musi taką metodę posiadać. Jest to podobny mechanizm do typu dynamic w C#: samo użycie danej metody powoduje wymóg jej istnienia.

0
#include "stdafx.h"
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <list>

class MojaKlasa : public std::vector< int >{};

int _tmain(int argc, _TCHAR* argv[])
{
	MojaKlasa roznica;
	MojaKlasa rezultat;
	MojaKlasa drugiRezultat;
 
	std::set_difference( rezultat.begin(), rezultat.end(),
	drugiRezultat.begin(), drugiRezultat.end(),
	std::inserter( roznica, roznica.begin() ) );
	return 0;
}

Tak to się skończy :).
Dzięki za rozjaśnienie tematu.

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