[C++] templates en libraries

Pagina: 1
Acties:
  • 100 views sinds 30-01-2008
  • Reageer

  • SWfreak
  • Registratie: Juni 2001
  • Niet online
Ik ben bezig om een library te maken met daarin allerlei nuttige algoritmes, zoals bijvoorbeeld sorteeralgoritmes. Nou zou dit geen probleem moeten zijn, ware het niet dat om zo generiek mogelijk te blijven ik natuurlijk templates wil gebruiken. Nu heb ik uit eerdere topics al verschillende oplossingen hiervoor gehaald:
  • mbv het C++ keyword "export" de template exporten.
    Dit werkt echter met maar 1 C++ compiler en niet met de VC++ die ik heb.
  • specifieke instantieringen van de template exporteren (void sorteer<int>() oid)
    Dit is echter precies niet de bedoeling van de library.
  • Alles in een .h file gooien.
    Hier is een hele berg nadelen aan, zoals bijvoorbeeld onleesbare files en samenvoegen van declaratie en definitie.
Ik vraag me dus af of jullie misschien ideeen hebben om een library te maken waarbij aan de volgende eisen voldaan wordt:
  • Scheiding van header en implementatie files
  • Eenvoudig als 1 entiteit te importeren in VC++
  • Closed source, dus alleen headers zijn openbaar.
De laatste eis is misschien niet helemaal haalbaar, dus als het niet anders mogelijk is kan deze eis buiten beschouwing gelaten worden.
Iemand suggesties?

Verwijderd

SWfreak schreef op 13 december 2003 @ 15:00:
• Scheiding van header en implementatie files
Include je cpp onder aan je header file.
• Eenvoudig als 1 entiteit te importeren in VC++
Namespaces?
• Closed source, dus alleen headers zijn openbaar.
Dit is niet mogelijk bij het gebruik van templates.

  • koli-man
  • Registratie: Januari 2003
  • Laatst online: 13-05 14:28

koli-man

Bartender!!!!

SWfreak schreef op 13 december 2003 @ 15:00:
aan de volgende eisen voldaan wordt:

• Closed source, dus alleen headers zijn openbaar.
Met een Insulator pattern ben je niet van je header file probleem af, maar is de implementatie van functies achter slot en grendel. (dacht ik weet het niet meer 100% zeker)

[ Voor 3% gewijzigd door koli-man op 13-12-2003 16:23 ]

Hey Isaac...let's go shuffleboard on the Lido - deck...my site koli-man => MOEHA on X-Box laaaiiiff


  • Eelis
  • Registratie: Januari 2003
  • Laatst online: 21-02-2015
.

[ Voor 99% gewijzigd door Eelis op 18-02-2015 20:02 ]


  • koli-man
  • Registratie: Januari 2003
  • Laatst online: 13-05 14:28

koli-man

Bartender!!!!

Heel even snel een copy paste, want ik moet eigenlijk al weg zijn. dit is ongeveer hoe het zou moeten werken.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//file ConcreteClass.h

class ConcreteClass_imp;

class ConcreteClass{
private:
    ConcreteClass_imp* _imp;
public:
    ConcreteClass();
    ConcreteClass(const ConcreteClass&);
    ConcreteClass& operator=(const ConcreteClass&);
    virtual ~ConcreteClass();

    void Operation();
};

//file ConcreteClass.cpp
#include &#8220;ConcreteClass.h&#8221;
#include &#8220;InternalServer.h&#8221;

class ConcreteClass_imp{
private:
    int Attribute;
public:
    ConcreteClass_imp ();
    ConcreteClass_imp (const ConcreteClass_imp &);
    ConcreteClass_imp & operator=(const ConcreteClass_imp &);
    virtual ~ConcreteClass_imp ();

    void Operation();
};

ConcreteClass_imp:: ConcreteClass_imp(){
    Attribute=0;
}

&#8230;&#8230;&#8230;..

ConcreteClass_imp::Operation(){
    InternalServer_Operation(Attribute);    //for example
}

ConcreteClass:: ConcreteClass(){
    _imp=new ConcreteClass_imp();
}

ConcreteClass_imp::~ ConcreteClass_imp{
    delete _imp;
}
void ConcreteClass::Operation(){
    _imp->Operation();
}

[ Voor 7% gewijzigd door koli-man op 13-12-2003 17:33 ]

Hey Isaac...let's go shuffleboard on the Lido - deck...my site koli-man => MOEHA on X-Box laaaiiiff


  • Eelis
  • Registratie: Januari 2003
  • Laatst online: 21-02-2015
.

[ Voor 103% gewijzigd door Eelis op 18-02-2015 20:02 ]


  • koli-man
  • Registratie: Januari 2003
  • Laatst online: 13-05 14:28

koli-man

Bartender!!!!

Je kunt zo je implementatie code verborgen houden, maar toch de headers beschikbaar stellen. Dat was IMHO wat hij nodig had.

Hey Isaac...let's go shuffleboard on the Lido - deck...my site koli-man => MOEHA on X-Box laaaiiiff


  • Eelis
  • Registratie: Januari 2003
  • Laatst online: 21-02-2015
.

[ Voor 99% gewijzigd door Eelis op 18-02-2015 20:02 ]


  • koli-man
  • Registratie: Januari 2003
  • Laatst online: 13-05 14:28

koli-man

Bartender!!!!

Eelis schreef op 13 december 2003 @ 18:03:
[...]

Dat lukt inderdaad bij normale classes wel, maar niet bij class templates. De definities van de member functions van de 'proxy' class moeten dan namelijk in de header staan, en daardoor de definities van de _imp class en de member functions daarvan ook.
Ow f*34k, je hebt gelijk.

Hey Isaac...let's go shuffleboard on the Lido - deck...my site koli-man => MOEHA on X-Box laaaiiiff


  • SWfreak
  • Registratie: Juni 2001
  • Niet online
Bedankt voor de reacties tot dus ver. Omdat het idee van koli-man niet werkte, ga ik nog even in op dat van xerix:
Include je cpp onder aan je header file.
Dit heb ik geprobeerd. Ik loop dan echter telkens tegen rare fouten aan.
Header:
C++:
1
2
3
4
5
6
7
8
9
10
11
namespace sort
{
    //...
    namespace helper
    {
        template<class T>
            void sort_merge_inplace_helper( T *, long, long );
        //....
    };
};
#include "sort_merge.cpp"

.cpp
C++:
1
2
3
4
5
6
7
8
#include "sort.h"
using namespace sort;
using namespace sort::helper;
template<class T>
void sort::helper::sort_merge_inplace_helper( T *array, long start, long end )
{
    //...
}

levert bij mij op:
error C2995: 'sort::helper::sort_merge_inplace_helper' : template function has already been defined
Ik heb echt geen idee hoe ik daar vanaf moet komen...
Namespaces?
Namespaces gebruik ik al zoals je ziet. Maar ik doel er eigenlijk meer op dat er een zeer beperkt aantal files is dat je moet includen/aan je project moet toevoegen. Bij een library is het vaak een kwestie van 1 header file en dan de .lib. Ik hoop dat zoiets ook mogelijk is dit geval...
Dit is niet mogelijk bij het gebruik van templates.
Daar was ik eerlijk gezegd al bang voor...

  • Orphix
  • Registratie: Februari 2000
  • Niet online
Misschien kan je er nog een obfuscator overheen laten lopen zodat je code iig minder toegangelijk is.

  • Eelis
  • Registratie: Januari 2003
  • Laatst online: 21-02-2015
.

[ Voor 99% gewijzigd door Eelis op 18-02-2015 20:02 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Sorry, maar wat je wil is precies waar export voor gemaakt is. In VC++ bevat een library (DLL of LIB) geen templates, hooguit template instantiaties. In VC++ zijn templates source-only.

Overigens, zelfs met export moet je rekening houden met het feit dat je templates niet zo closed zijn als je zou denken. Om two-phase name lookup te laten werken moeten je sources beschikbaar zijn, in een of andere vorm.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • SWfreak
  • Registratie: Juni 2001
  • Niet online
Eelis schreef op 13 december 2003 @ 20:01:
Probleem: de files includen elkaar.

Oplossing: verwijder de '#include "sort.h"' regel uit de .cpp.

Overigens is de .cpp extensie nu enigszins verwarrend, aangezien deze niet meer los wordt gecompileerd. Het is gebruikelijker om deze dan .inl of .inc of iets dergelijks te noemen.

Waar je verder rekening mee moet houden bij het schrijven van deze .inl/.inc is dat hij via de header onderdeel wordt van de translation unit van client-code. Het is dus zaak om de code in deze file als header-code te schrijven, en dus bijvoorbeeld niet de namespace te laten vervuilen met dingen als 'using namespace sort;'.
Nee, dat is het probleem niet. Zonder het includen van de header krijg ik namelijk foutmeldingen dat de namespace niet bestaat. Het mogelijke probleem van een infinite loop met includen heb ik al opgelost met een #ifndef -> #define constructie.
Het is trouwens nodig om die using erin te knallen, omdat ik anders weer andere errors krijg. Dit komt doordat in sort_merge.cpp weer functies uit sort_utils.cpp gebruikt worden etc.
MSalters schreef op 13 december 2003 @ 20:17:
Sorry, maar wat je wil is precies waar export voor gemaakt is. In VC++ bevat een library (DLL of LIB) geen templates, hooguit template instantiaties. In VC++ zijn templates source-only.

Overigens, zelfs met export moet je rekening houden met het feit dat je templates niet zo closed zijn als je zou denken. Om two-phase name lookup te laten werken moeten je sources beschikbaar zijn, in een of andere vorm.
Ik weet dat export daar voor is, maar dat kan ik niet gebruiken (zie topic start).

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

SWfreak schreef op 13 december 2003 @ 22:35:
[...]

Ik weet dat export daar voor is, maar dat kan ik niet gebruiken (zie topic start).
Hij geeft dan ook dat je probleem niet op te lossen is zonder export ;)

Professionele website nodig?


Verwijderd

Om je header en implementatie bestanden bij het gebruik van templates toch gescheiden te houden kun je gebruik maken van de constructie die ik hieronder heb neergezet. Dit is zo'n beetje de standaard oplossing die aangehouden wordt, zolang export in de meeste compilers niet geimplementeerd is.

Header file:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
#ifndef ALGORITHM_H
#define ALGORITHM_H

namespace stl
{
    template<class InputIterator, class Functor>
    void sort(InputIterator first, InputIterator last, Functor func);
};

#include "algorithm.inl"

#endif /* ALGORITHM_H */


Implementatie file:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef ALGORITHM_INL
#define ALGORITHM_INL

#ifndef ALGORITHM_H
#include "algorithm.h"
#endif /* ALGORITHM_H */

template<class InputIterator, class Functor>
void stl::sort(InputIterator first, InputIterator last, Functor func)
{
    /* TODO: implementation */
}

#endif /* ALGORITHM_INL */

  • Ericston
  • Registratie: Maart 2001
  • Laatst online: 30-03 17:41
SWfreak schreef op 13 december 2003 @ 19:10:
[...]

error C2995: 'sort::helper::sort_merge_inplace_helper' : template function has already been defined
Ik heb echt geen idee hoe ik daar vanaf moet komen...

[...]
Volgens mij moet je in VC++ dan zorgen dat de cpp file niet gecompiled wordt.
In 7.1: Properties van cpp file -> Excluded from build -> Yes.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 15:32

.oisyn

Moderator Devschuur®

Demotivational Speaker

Maw, gewoon niet de cpp extensie gebruiken, dan is het ook nog eens makkelijker te begrijpen voor anderen ;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

.oisyn schreef op 14 december 2003 @ 22:30:
Maw, gewoon niet de cpp extensie gebruiken, dan is het ook nog eens makkelijker te begrijpen voor anderen ;)
* curry684 herinnert zich dat ie in de historie van P&W vast al 20-30 keer heeft gezegd dat '.inl' een hele mooie extensie is voor inline files zoals templateimplementaties O-)

Professionele website nodig?


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Verwijderd schreef op 14 december 2003 @ 20:53:
Om je header en implementatie bestanden bij het gebruik van templates toch gescheiden te houden kun je gebruik maken van de constructie die ik hieronder heb neergezet. Dit is zo'n beetje de standaard oplossing die aangehouden wordt, zolang export in de meeste compilers niet geimplementeerd is.

Header file:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
#ifndef ALGORITHM_H
#define ALGORITHM_H

namespace stl
{
    template<class InputIterator, class Functor>
    void sort(InputIterator first, InputIterator last, Functor func);
};

#include "algorithm.inl"

#endif /* ALGORITHM_H */


Implementatie file:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef ALGORITHM_INL
#define ALGORITHM_INL

#ifndef ALGORITHM_H
#include "algorithm.h"
#endif /* ALGORITHM_H */

template<class InputIterator, class Functor>
void stl::sort(InputIterator first, InputIterator last, Functor func)
{
    /* TODO: implementation */
}

#endif /* ALGORITHM_INL */
Bijna, maar zo werkt het niet. Je mist "inline". Dat moet je gebruiken, omdat je anders de One Definition Rule overtreedt.

.inl files met header guards beschermen is net zo overbodig als .cpp files met header guards beschermen, of .jpg files :) . Ze worden toch nooit twee keer in een Translation unit geinclude; ze worden precies net zo vaak geinclude als de header file die de interface declareert.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Verwijderd

Uit The C++ Programming Language Third Edition van Bjarne Stroustrup:
The inline specifier is a hint to the compiler that it should attempt to generate code for a call [...] inline rather than laying down the code for the function once and then calling through the usual function call mechanism.
Dus inline maakt hier niets uit. Mijn code is ook legaal, aangezien in de header file alleen een (forward) declaration wordt gemaakt en in de implementation file wordt de implementation gegeven. Het gebruik van guards in de implementation file zorgt er voor dat deze normaal te compileren is, dus zo geheel overbodig als jij het stelt is het niet.

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Oepsie. inline heeft meer betekenis dan hierboven beschreven. In het bijzonder heeft inline tot gevolg dat de ODR niet meer geldt, en het is dus meer dan een hint. Alleen was ik effe vergeten dat de ODR uitzondering ook geldt voor template. |:(

Wat jij stelt, header file vs implementation file geldt niet meer omdat je de implementation file meerdere keren include per programma. De ODR werkt niet op basis van files oid. (De C++ standaard gaat niet eens van files uit) De ODR stelt dat elke definition in maximaal een Translation Unit (TU) mag voorkomen, en daarin maar een keer. De conventie is dat een enkele .cpp file met alle includes daarin samen een Translation Unit is. Jouw algorithm.h komt dus in meerdere TU's terecht, en je .inl ook. Elke functie definitie daarin - met uitzondering van inline en template - levert je dus een ODR overtreding op.

De reden dat template geen ODR overtreding oplevert is omdat het in '98 al bekend was dat export niet meteen beschikbaar zou zijn. Het huidige mechanisme zorgt er effectief voor dat templates toch gebruikt kunnen worden.

Wat je over header guards in implementation files stelt is onzin. Ten eerste is het onzinnig om een .inl file apart te compileren - als TU draagt de .inl geen definities bij (omdat de template functie nergens in de .inl wordt geinstantieerd ) en ten tweede, zelfs als je dat doet heb geen header guards nodig; het doel van een hedaer guard is om te voorkomen dat een file twee keer in een TU komt. Een file die je explciet aan de compiler voert is een TU op zich.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Verwijderd

Templates != Closed Source...

De enige manier om een template closed source te maken is door hem af te leiden van een "base class" en het meeste van de implementatie daarin doen... echter de template functies kunnen NOOIT closed source zijn... (de template zelf wordt daar dus ook niet closed source van, maar z'n base misschien wel)

Templates is iets wat tijdens het compileren wordt verwerkt, en niet door de linker. Wat jij wil is een library maken, welnu, dat kan, maar je templates zul je als h file mee moeten leveren, met de volledige source code.

[ Voor 10% gewijzigd door Verwijderd op 16-12-2003 17:13 ]


Verwijderd

Niet helemaal correct. :) De ODR stelt dat twee definities van een class, template,inline function, etc. toegelaten worden als voorbeelden van dezelfde (unieke) definitie als ze a) in verschillende translation units voorkomen, b) ze token-voor-token identiek zijn en c) als de betekenis van die tokens gelijk is in beide translation units.

Het nut van guards in de implementation file moet ik even opzoeken. Ik heb het ooit ergens gelezen en natuurlijk kan ik dat nu niet meer terug vinden! :( Dus het antwoord daarop moet ik je nog schuldig blijven! :)
Pagina: 1