template, class, külön fájlokban...

Fórumok

hi,

volna egy library, s egy class aminek adatokat kéne tárolnia egy linked list of structures szerűségben. mivel, még úgyis szükség lessz rá, készítettem egy class-t, hogy az kezelje a listát.. template, mert több féle elemet akarok tárolni.. aztán itt vany a gond, linkelésnél egy halom undefined reference hibaüzenet.. keresgélés után megtaláltam, hogy az export lenne a legjobb, de azt meg szinte egy fordító sem támogatja :(... a typedef-es és a c++ fájl bele a headerbe is próbáltam de egyik se akar működni...


/**
 * @file core/linkedlist.h++
 * A class for linked list of structures
 */

#ifndef LINKEDLIST_H
#define LINKEDLIST_H

namespace DW {

template<class type>
class LinkedList {
	private:
		struct ListStruct {
			type item;
			ListStruct * next;
		} *start, *last;
		unsigned int length;
	public:
		LinkedList();
		~LinkedList();
		
		type * Add();
		type * Add(type data);
		
		type & operator [] (unsigned int index);
		
		unsigned int GetLength() { return length; }
		
		void Remove(unsigned int id);

};


typedef LinkedList<struct DirtYOptions> OptionsLinkedList;

}

#endif

/**
 * @file core/linkedlist.c++
 * A class for linked list of structures
 */

#include "linkedlist.h++"
#include <stdexcept>

using namespace DW;

template<class type>
LinkedList<type>::LinkedList()
{
	length = 0;
	*start = NULL;
	*last = NULL;
}

template<class type> 
LinkedList<type>::~LinkedList()
{
	ListStruct * current, next;
	current = start;
	
	while (current != NULL) {
		next = current->next;
		delete current;
		current = next;
	}
}

template<class type> 
type * LinkedList<type>::Add()
{
	last = last->next = new ListStruct;
	length++;
	return &last->item;
}

template<class type>
type * LinkedList<type>::Add(type data)
{
	last = last->next = new type;
	last->item = data;
	length++;
	return &last->item;
}

template<class type>
type & LinkedList<type>::operator[](unsigned int index)
{
	if (index < 0 || index > length) throw std::out_of_range::out_of_range("DW::LinkedList::operator []");
	ListStruct * current;
	current = start;
	for (unsigned int i = 0; i < index; i++)
		current = current->next;
	return current->item;
}


/**
 * @file core/parameters.h++
 * Header for parameter-handling routines
 */

#ifndef PARAMETERS_H
#define PARAMETERS_H

#include <getopt.h>
#include <iostream>

#include "linkedlist.h++"
//template<class type> struct LinkedList {unsigned int num; };

namespace DW {


	struct DirtYOptions {
		char         short_option;    ///< Short parameter <em>(eg: -c)</em>
		std::string  long_option;     ///< Long parameter <em>(eg: --something)</em>
		std::string  help_text;       ///< Help text displayed for the parameter
		int         *variable_change; ///< Variable to change, when the option specified
		int          variable_set_to; ///< The value, that variable_change set to
		bool         has_argument;    ///< <b>True</b>, if the parameter has an argument
		std::string *argument_change; ///< The variable, that gets the argument
	};              ///< Stores information for processing program parameters


class Params
{
	public:
		Params();
//		~Params();
		
		/**
		 * @brief Adds a parameter to the list.
	 	 * @param short_option the short option for that parameter <em>(eg: -c)</em>. Set it to 0, if you do not want to have short option.
		 * @param long_option the long option for that parameter <em>(eg: --something)</em>
		 * @param help_text the message that displayed to the user, when running with <em>--help</em>
		 * @param var_change a pointer to an int variable, that's get changed when the user specifies the option
		 * @param var_set_to sets var_change to the specified value when the option specified
		 * @param has_argument if true, DW will look for a argument for that option <em>(eg: --something boo)</em>
		 * @param argument_change a pointer to an std::string variable that gets the argument value. <b>Note:</b> The program gets every argument as a string. If you need a numerical value, hou have to convert it manually.
		 */
		void AddParameter(char short_option, std::string long_option, std::string help_text, int *var_change, int var_set_to, bool has_argument=false, std::string *argument_change=NULL);
		void SetInfo(std::string info); ///< Sets @link DW_Params::info_text info_text @endlink
		void SetHelp(std::string help); ///< Sets @link DW_Params::help_text help_text @endlink
		/**
		 * @brief Run the check on the program's parameters.
		 * @note SetHelp(), SetInfo() and all AddParameter() functions have to ran before you execute this command.
		 * @param argc and @param argv are the parameters, that the main function gets (eg: <pre style="display: inline;">int main(int argc, char* argv[]) { ...</pre>)
		 */
		void Run(int argc, char* argv[]);
	private:
		OptionsLinkedList args;       ///< Contains the parameters
		std::string help_text; ///< A string, that displayed when the user runs the program with <em>--help</em>
		std::string info_text; ///< A string, that displayed when the user runs the program with <em>--usage</em> (usually contains the program name and version)

};
}

#endif

/**
 * @file core/parameters.c++
 * Handling applications parameters
 * Routines to handle the application's parameters
 */

#include <cstdlib>
#include <cassert>
#include "parameters.h++"

using namespace DW;

Params::Params()
{
	//args.num = 0;
	help_text = "Undefined";
	info_text = "Undefined";
}

void Params::SetInfo(std::string info)
{
	info_text = info;
} 

void Params::SetHelp(std::string help)
{
	help_text = help;
}


void Params::AddParameter(char short_option, std::string long_option, std::string help_text, int *var_change, int var_set_to, bool has_argument, std::string *argument_change)
{
	assert(long_option!="");
	assert(var_change);
	if (has_argument) assert(argument_change);
	

	DirtYOptions * opts = args.Add();
	opts->short_option = short_option;
	opts->long_option = long_option;
	opts->help_text = help_text;
	opts->variable_change = var_change;
	opts->variable_set_to = var_set_to;
	opts->has_argument = has_argument;
	opts->argument_change = argument_change;

}

void Params::Run(int argc, char* argv[])
{
	std::cout<<"Info text: "<<info_text<<std::endl;
	std::cout<<"Help text: "<<help_text<<std::endl;
	for (unsigned int i=0; i<args.GetLength(); i++)
		std::cout<<i<<"th parameter: "<<args[i].long_option<<std::endl;
	std::cout<<std::endl;
	for (int i=0; i<argc; i++)
		std::cout<<i<<"th argument: "<<argv[i]<<std::endl;
	exit(0);
}

ez a library, ehez egy példa program:


#include <parameters.h++>

int main(int argc, char* argv[])
{
        DW::Params Params;
        int f = 0;

        Params.SetHelp("This is a test program. And this is it's help text. Read carefully!");
        Params.SetInfo("TesT program v. 0.0");

        Params.AddParameter(0, "foobar", "Something foo+bar=foobar!!! :@", &f, 1);
        
        Params.Run(argc,argv);

        return 0;
}

és a hibaüzenetek:

/tmp/cc5Fwx7x.o: In function `DW::Params::~Params()':
test.cpp:(.text._ZN2DW6ParamsD1Ev[DW::Params::~Params()]+0x57): undefined reference to `DW::LinkedList<DW::DirtYOptions>::~LinkedList()'
test.cpp:(.text._ZN2DW6ParamsD1Ev[DW::Params::~Params()]+0x70): undefined reference to `DW::LinkedList<DW::DirtYOptions>::~LinkedList()'
build/default/core//libdw_core.a(parameters.o): In function `DW::Params::Run(int, char**)':
../src/core/parameters.c++:87: undefined reference to `DW::LinkedList<DW::DirtYOptions>::operator[](unsigned int)'
build/default/core//libdw_core.a(parameters.o): In function `DW::Params::AddParameter(char, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int*, int, bool, std::basic_string<char, std::char_traits<char>, std::allocator<char> >*)':
../src/core/parameters.c++:61: undefined reference to `DW::LinkedList<DW::DirtYOptions>::Add()'
build/default/core//libdw_core.a(parameters.o): In function `Params':
../src/core/parameters.c++:36: undefined reference to `DW::LinkedList<DW::DirtYOptions>::LinkedList()'
../src/core/parameters.c++:41: undefined reference to `DW::LinkedList<DW::DirtYOptions>::~LinkedList()'
../src/core/parameters.c++:36: undefined reference to `DW::LinkedList<DW::DirtYOptions>::LinkedList()'
../src/core/parameters.c++:41: undefined reference to `DW::LinkedList<DW::DirtYOptions>::~LinkedList()'

előre is köszi minden segítséget... ja, és most kb 1 óráig nem leszek internet közelben...

Hozzászólások

A példaprogramban rossz az include, "parameters.h++" kellene. (Mondjuk, ez nem oldja meg a te problémádat.)

KisKresz

Nem bogarasztam vegig, de szinte biztos vagyok benne, hogy az a baj, hogy template tagfveket akarsz kolon object-be forditani. Ezen azt ertem hogy van hozza kulon cpp fajl es nem a .h-ban van az implementacio.
Ilyet nem lehet, hiszen template-et nem lehet leforditani, majd a folhasznalo kod forditasa soran fogja a fordito a template parametereket fololdani, es kodot generalni.
Tipp : nezd meg az stl hogy van megcsinalva. pl stl_vector.h
==
`Have some wine,' the March Hare said in an encouraging tone.
Alice looked all round the table, but there was nothing on it but tea.

A linkedlist konstruktorát és destruktorát helyre kell rakni (a mutatókkal van gond).
Utána a linkedlist.h++ utolsó előtti sorába

#include "linkedlist.c++"

Ez csúnya hack, de így lefordul. (Persze, ezek után a linkedlist.c++-t nem szabad külön fordítani).
Viszont a példaprogram nálam segmentation fault-ra futott, szóval ott még lehet valami gond...

KisKresz

#include "linkedlist.c++"

Ez csúnya hack, de így lefordul. (Persze, ezek után a linkedlist.c++-t nem szabad külön fordítani).

Miert nem teszed be kezzel a linkedlist.c++ tartalmat a .h-ba es torlod ki a .c++ fajlt? A ketto nagyjabol ugyanaz, csak nincs folos c++ fajlod a projectben amit "nem szabad leforditani", amugy meg mindenki igy szokta, igy csinalja az stl is. Jah es nem kell c++ fajlt includolni.
==
`Have some wine,' the March Hare said in an encouraging tone.
Alice looked all round the table, but there was nothing on it but tea.

hmm... linkedlist.h++-ba beraktam az #endif elé az #include "linkedlist.c++"-t, mutatók fix LinkedList constroctorában & destructorában, és LEFORDUL! pedig már próbáltam ezt a h-ba betevős cuccot... de ezek szerint akkor a mutatókkal volt gondja.. csak azt nem értem, hogy a beküldött kód, az úgy lefordult, csak a linkelésnél szált el, tehát ott mért nem problémázott a pointerekkel?

amugy pedig itt száll el:
Program received signal SIGSEGV, Segmentation fault.
0x08049950 in DW::LinkedList<DW::DirtYOptions>::Add (this=0xbfe301bc) at ../src/core/linkedlist.c++:57
57              last = last->next = new ListStruct;

de mindjárt utána is nézek...

I hate myself, because I'm not open-source.

Gyerekek....

Na szoval irtatok jot is meg rosszat is. A C++ templatek mogott nem all leforditott kod, ez igaz.
Tehat ha C++ templateket akartok csinalni akkor vagy a headerbe teszitek, es mindenhova
beincludaljatok, vagy ha szebben akarjatok csinalni, kulonosen ha kulon objectben
akkor irni kell egy instanciációs részt hozzá, ahol gyakorlatilag kodot rendelsz hozza

PL:
template
class A
{
...
};

ez mehet a headerbe (.h)

A metodusok definicioi a .cpp be, es a cpp vegere be kell tenni az ominozus reszt:

template class A;
template class A;
template class A;

stb stb. Itt mindenfele tipust fel kell sorolni amit hasznalni szeretnenk a template ben,
es a kod tulajdonkeppen ezekhez fog legeneralodni.
Ennyi.

A te bajod valoszinuleg ez, egyeb hibakat nem sorolok ugyanis a kodot nem futottam vegeig,
nem akartam egy orat raszanni :-)
de a kidobott hibauzenetek alapjan ez a baj.

legközelebb figyelhetnél, hogy a HTML miatt a < > közti rész nem igazán jelenik meg... másrészt nem tudom mennyire szerencsés az, ha a LinkedList függ Params-tól a struct miatt, és a Params függ a LinkedList-től, mint classtól...

I hate myself, because I'm not open-source.

Ezt is lehet, c++ fajlt includolni is lehet, es mind mukodik is.

A kerdes a kod kesobbi ujra felhasznalhatosaga, atlathatosaga stb.
Ezzel az az ossz problemam, hogy valoszinuleg a lib irasakor nem tudom milyen template parameterekkel akarjak hasznalani, ezert irok template libet. Vagyis folhasznalaskor modosithatom a template class c++-jat hozzarakva a szukseges "ominozus" reszt, ami nem szerencses.

Persze ez mar nem a mukodesrol, hanem stilusrol szol.
==
`Have some wine,' the March Hare said in an encouraging tone.
Alice looked all round the table, but there was nothing on it but tea.

Lehet, hogy működik, de alapvetően ellent mond a generikus programozás alapelveinek.

Itt nem csak arról van szó, hogy nem akarod külön megírni char-ra meg int-re. Pont az a lényeg, és azért írsz template-es LinkedListet, mert nem tudod, hogy miket fogsz belerakni.

Egyébként meg nem nagyon értem, hogy miért szeretitek feltalálni a kereket mégegyszer, és miért nem jó az stl-es list...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o