Metoda szablonowa zwracająca składowe klasy

0

Cześć, mam program który posiada klasę Pojazd. Klasa pojazd posiada składowe int przebieg, float cena, są one prywatne. Chciałem stworzyć metodę szablonową, która zwraca te dwie składowe i można ją wywołać z main w którym przechowuję Pojazdy w wektorze parkingFabryka. Napisałem taki kod, ale niestety wyskakuję błąd. (Cały program ma ponad 1000 linijek, więc poniżej jest tylko uproszczony kod)

Plik Pojazd.h

class Pojazd
{
public:
    template<typename T>
    T zwroc(char info);

protected:
    float cena;
    int przebieg;
};

Plik Pojazd.cpp

template<typename T>
T Pojazd::zwroc(char info)
{
    switch (info)
    {
        case 'c':
            return cena;
        case 'p':
            return przebieg;
    }
}

Plik main.cpp

vector<unique_ptr<Pojazd>> parkingFabryka;
cout << "Przebieg" << parkingFabryka[0]->zwroc<int>('p') << endl; //tutaj wyskakuje poniższy bład
cout << "Cena"  << parkingFabryka[0]->zwroc<float>('c') << endl; //to tez nie dziala

Błąd

C:/Users/Dell/Documents/Program/main.cpp:342: undefined reference to `int Pojazd::zwroc<int>(char)'
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
2

Umieść implementację w pliku nagłówkowym, poprzedź ją inline jeżeli będziesz ją chciał mieć poza klasą.

0

@alagner: Dziękuje, jak umieściłem implementacje w Pojazd.h to poszło. Mam jeszcze pytanie odnośnie inline. Czy inline należy dopisać tylko w pliku Pojazd.cpp, a w Pojazd.h nic nie zmieniać? Teraz robię to tak, ale nie działa (próbowałem dopisać inline również w Pojazd.h, ale też nie idzie)

Pojazd.cpp

template<typename T>
inline T Pojazd::zwroc(char info)
{
    switch (info)
    {
        case 'c':
            return cena;
        case 'p':
            return przebieg;
    }
}
2

To jest trochę bardziej skomplikowane, szczegóły masz tu:
https://stackoverflow.com/questions/115703/storing-c-template-function-definitions-in-a-cpp-file

TLDR: To co masz w Pojazd.cpp w ogóle wyrzuć. Ciało szablonu funkcji musi być w pliku nagłówkowym. Zasadniczo masz dwie opcje:

//plik H:
struct S
{
   template <typename T>
   T doStuff();
};

template<typename T>
inline T S::doStuff()
{
//costam
}

tudzież:

//plik H:
struct S
{
   template <typename T>
   T doStuff() //to jest implicit inline
   {
     //costam
   }
};


Przy czym Twój design (z tym casem w środku) jest do chrzanu z kilku względów:
a. to Ci się kompiluje tylko dlatego, że int i float są konwertowalne między sobą. Dołóż inny typ zwracany, który się nie konwertuje między tymi dwoma i Ci się to rozleci.
b. niezwracanie niczego kiedy nie trafisz w case'a to UB.
c. konwencje nazewnicze bardzo słabe, ale o tym to aż szkoda gadać.

Jak bardzo chcesz się tak bawić koniecznie to użyj
a. if constexpr i type_traits z C++17
b. specjalizacji/tag dispatchingu ale nadal imho ma to mały sens w tym kontekście.

Przykłady:
https://godbolt.org/z/49a1TjxWo

2

Może coś w tym stylu:

#include <iostream>
#include <string>
#include <map>
using namespace std;

class Car
{
	public:
	Car(const string &model,float price,int mileage):model(model),price(price),mileage(mileage) {}
	private:
	string model;	
	float price;
	int mileage;
	static ostream &putmodel(ostream &s,const Car &car) { return s<<car.model; }
	static ostream &putprice(ostream &s,const Car &car) { return s<<car.price; }
	static ostream &putmileage(ostream &s,const Car &car) { return s<<car.mileage; }
	typedef ostream &putvalue(ostream &s,const Car &car);
	static map<string,putvalue*> F()
	{
		static map<string,putvalue*> factory
		{
			{"model",&putmodel},
			{"price",&putprice},
			{"mileage",&putmileage},
		};
		return factory;
	}
	public:
	static ostream &putproperty(ostream &s,Car &car,const string &name) { return F()[name](s<<name<<": ",car); }
	static ostream &putallproperty(ostream &s,Car &car)
	{
		for(map<string,putvalue*>::const_iterator i=begin(F());i!=end(F());++i) putproperty(s,car,i->first)<<endl;
		return s; 
	}
};

int main()
{
	Car car("Audi",100000,30000);
	Car::putallproperty(cout,car);
	return 0;
}
1

Dla mnie pytanie to Problem XY, czyli źle zadane pytanie.
Napisz po co ci taki feature, jaką funkcjonalność ma realizować ta funkcja.

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