hallgeirl Skrevet 19. september 2010 Del Skrevet 19. september 2010 (endret) Du vil vel gjerne kalle sum<T, P> (eks. sum<double, double>) istedetfor bare sum. Skal den ikke kunne ta de typene ut ifra sammenhengen? Men hva om han kaller sum(5)? Hvilken av sum-funksjonene skal kalles? Begge er mulige. Dessuten, hva slags datatype skal brukes? int? long? short? byte? Umulig å bestemme utifra kallet uten en hel masse eksplisitte regler for hvordan slike tvetydigheter skal behandles. Noe som iallefall JEG ville styrt unna, om jeg skulle designet språket. Basert på dette så stiller jeg meg tvilsom til det. Endret 19. september 2010 av hallgeirl Lenke til kommentar
TheMaister Skrevet 19. september 2010 Del Skrevet 19. september 2010 (endret) Var visst ikke så enkelt. stackoverflow.com har dog svaret: http://stackoverflow.com/questions/3744400/decltype-with-a-variadic-template-function #include <iostream> #include <type_traits> using namespace std; template <class T> typename add_rvalue_reference<T>::type val(); template <class T> struct id { typedef T type; }; template <class T, class... P> struct sum_type; template <class T> struct sum_type<T> : id<T> {}; template <class T, class U, class... P> struct sum_type<T, U, P...> : sum_type< decltype(val<const T&>() + val<const U&>()), P... > {}; template <class T> T sum(const T& in) { return in; } template <class T, class... P> typename sum_type<T, P...>::type sum(const T& t, const P&... p) { return t + sum(p...); } int main() { cout << sum(5, 10.0, 22.2) << endl; } Hvem sa at template metaprogrammering ikke var kult? >_< Endret 19. september 2010 av TheMaister Lenke til kommentar
TheMaister Skrevet 19. september 2010 Del Skrevet 19. september 2010 Hvordan ville tilsvarende kode sett ut i e.g. C# eller Java egentlig? (Hvis det går) Lenke til kommentar
TheMaister Skrevet 19. september 2010 Del Skrevet 19. september 2010 (endret) Høhø, la til rvalue semantics i tillegg. #include <iostream> #include <type_traits> using namespace std; template <class T> typename add_rvalue_reference<T>::type val(); template <class T> struct id { typedef T type; }; template <class T, class... P> struct sum_type; template <class T> struct sum_type<T> : id<T> {}; template <class T, class U, class... P> struct sum_type<T, U, P...> : sum_type< decltype(val<const T&>() + val<const U&>()), P... > {}; template <class T> T sum(const T& in) { return in; } template <class T> typename remove_reference<T>::type&& sum(T&& in) { return move(in); } template <class T, class... P> typename sum_type<T, P...>::type sum(const T& t, const P&... p) { return t + sum(p...); } template <class T, class... P> typename sum_type<T, P...>::type sum(T&& t, P&&... p) { return move(t) + sum(p...); } int main() { cout << sum(5, 10.0, 22.2, 30) << endl; } Nå ser det da veldig vakkert ut ... xD Hm :v Virker ikke som den gjør ting helt riktig, men, men Endret 19. september 2010 av TheMaister Lenke til kommentar
hallgeirl Skrevet 19. september 2010 Del Skrevet 19. september 2010 *grøss* I second that. Lenke til kommentar
worseisworser Skrevet 19. september 2010 Del Skrevet 19. september 2010 (endret) Hvordan ville tilsvarende kode sett ut i e.g. C# eller Java egentlig? (Hvis det går) Jeg har ikke helt fått med meg det du nevnte om å også returnere type i tillegg til sum, men i Common Lisp kan en summere "hva som helst" slik: CL-USER> (defun sum (&rest args) (apply #'+ args)) SUM CL-USER> (sum 5 10.0 22.2 30) 67.2 CL-USER> (sum 1/2 3/4) 5/4 CL-USER> (sum #C(5 -3) #C(5/3 7)) ;; komplekse tall #C(20/3 4) CL-USER> edit: De som kjenner til dette fra før vet sikkert at det å lage en SUM funksjon som dette har liten hensikt da funksjonen + allerede aksepterer et vilkårlig antall argumenter (&REST). Endret 19. september 2010 av worseisworser Lenke til kommentar
TheMaister Skrevet 19. september 2010 Del Skrevet 19. september 2010 Ja, klart. Dette er bare et forsøk på å pushe syntaksen i et statisk typed språk som C++. Så vidt jeg har skjønt er lisp dynamisk typed, og da finnes ikke problemstillingen. Lenke til kommentar
GeirGrusom Skrevet 20. september 2010 Del Skrevet 20. september 2010 (endret) En kan ikke bruke pluss, minus gange eller dele i generics i C#. Så public T Sum<T>(T a, T b) { return a + b; } Er ulovlig. Men C# tar datatypen ut av sammenhengen, så hvis du skriver for eksempel slik: public T Sum<T>(T a, T b, params T rest) // Definer en funksjon som tar inn minst to tall { decimal total; total = (decimal)a + (decimal)b; foreach(var item in rest) total += (decimal)item; return (T)total; } public void Main() { var dec = Sum(1, 2, 3, 7); // var er det samme som auto i C++0x etter det jeg har forstått av auto // dette burde returnere et integer. } en må bruke decimal eller en annen datatype, ettersom + er udefinert på T. Det hadde vært kjekt om en kunne lagt på en "Arithmetic" constraint eller noe, men det går altså ikke. Generics er mer egnet for collections og delegates, og ikke så mye for beregning. edit: glemte at C# er dynamisk nå, så nå kan man lage noe slikt som fungerer. public dynamic Sum(dymaic a, dynamic b, params dynamic values) { dynamic res = a + b; foreach(var item in values) res += item; return res; } dynamic har selvsagt ulempen av å være run-time sjekket, og er derfor noe tregere enn generics. Jeg vet ikke hva utbyttet av dynamic er kontra å bruke decimal med tanke på ytelse, siden decimal er software 128-bit heltall (kanskje hardware, med tanke på prosessor-utvidelser, men jeg har ikke sjekket) Endret 20. september 2010 av GeirGrusom Lenke til kommentar
worseisworser Skrevet 20. september 2010 Del Skrevet 20. september 2010 (endret) Ja, klart. Dette er bare et forsøk på å pushe syntaksen i et statisk typed språk som C++. Så vidt jeg har skjønt er lisp dynamisk typed, og da finnes ikke problemstillingen. Mh, vel det er vel en slags hybrid av slag(#1); "normalen" er dynamisk eller sterk typing -- og compile-time (og inferred; "type inferrence") type-informasjon brukes i større grad til optimalisering i så måte at generert kode som ellers ville gjort run-time type-sjekking vil kunne fjernes om en ønsker det. Denne gjør et kall til en intern funksjon, GENERIC-+, som altså håndterer "hva som helst" og gjør run-time type-sjekking: ; SLIME 2010-09-18 CL-USER> (defun test (x y) (+ x y)) TEST CL-USER> (disassemble 'test) ; disassembly for TEST ; 03F3F1DF: 4C8D1C25E0010020 LEA R11, [#x200001E0] ; GENERIC-+ ; no-arg-parsing entry point ; E7: 41FFD3 CALL R11 ; EA: 480F42E3 CMOVB RSP, RBX ; EE: 488BE5 MOV RSP, RBP ; F1: F8 CLC ; F2: 5D POP RBP ; F3: C3 RET NIL CL-USER> ..mens denne genererer "inline" kode som summerer, kun, FIXNUMs (samme bakenforliggende eller maskinvaremessige størrelse som int i C) uten å gjøre run-time type-sjekking i det hele tatt: CL-USER> (defun test (x y) (declare (fixnum x y)) (the fixnum (+ x y))) STYLE-WARNING: redefining COMMON-LISP-USER::TEST in DEFUN TEST CL-USER> (disassemble 'test) ; disassembly for TEST ; 03FB2D1F: 4801FA ADD RDX, RDI ; no-arg-parsing entry point ; 22: 488BE5 MOV RSP, RBP ; 25: F8 CLC ; 26: 5D POP RBP ; 27: C3 RET NIL CL-USER> #1: ANSI-standaren er rimelig åpen eller fri m.t.p. hvordan en implementasjon skal være her. Endret 20. september 2010 av worseisworser Lenke til kommentar
Sir Zu Zwat Skrevet 27. september 2010 Del Skrevet 27. september 2010 Hei programmerere, Står litt fast her, så trenger litt hjelp. Skal forklare hva som skjer når jeg kjører kodesnutten i main.cpp. Forstår deler av det. Hvorfor blir kopikonstruktøren kallet 4 ganger? Hvorfor blir to av dem fjernet av destruktøren med en gang, mens de to andre blir fjernet etter {} ? Takk på forhånd! vektor.h //--------------------------------------------------------------------------- #ifndef VektorH #define VektorH //--------------------------------------------------------------------------- class Vektor{ public: Vektor(); Vektor(int start, int antal); Vektor(const Vektor& org); ~Vektor(); //operatorar Vektor operator+(const Vektor& v) const; const Vektor& operator=(const Vektor& v); // metodar Vektor metode1(Vektor v); Vektor metode2(Vektor& v); Vektor& metode3(Vektor v); Vektor& metode4(Vektor& v); Vektor* metode5(Vektor& v); private: const int i1; int ant; int *p; int nr; static int neste; }; #endif vektor.cpp #include "Vektor.h" #include <iostream> using namespace std; //--------------------------------------------------------------------------- int Vektor::neste = 1; // gir verdi til statisk variabel Vektor::Vektor(): ant(0), i1(1), p(0){ nr= neste++; cout << "Standard konstruktør. Nr: " << nr << endl; } Vektor::Vektor(int start, int antal): i1(start), ant(antal) { nr= neste++; cout << "Spesial konstruktør. Nr: " << nr << endl; p = new int[ant]; } Vektor::Vektor(const Vektor& org): i1(org.i1), ant(org.ant){ nr= neste++; cout << "Kopikonstruktør. Nr: " << nr << endl; p = new int[ant]; for (int i = 0; i < ant; i++){ p[i] = org.p[i]; } } Vektor::~Vektor(){ cout << "Destruktør. Nr: " << nr << endl; delete[] p; } //operatorar Vektor Vektor::operator+(const Vektor& v) const{ cout << "Operator+" << endl; Vektor temp(*this); for (int i = 0; i < ant; i++){ temp.p[i] += v.p[i]; } return temp; } const Vektor& Vektor::operator=(const Vektor& v){ cout << "Tildelingsoperator" << endl; if (this != &v){ delete[] p; ant = v.ant; p = new int[ant]; for (int i = 0; i < ant; i++){ p[i] = v.p[i]; } } return *this; } Vektor Vektor::metode1(Vektor v){ return v; } Vektor Vektor::metode2(Vektor& v){ return v; } /* Vektor& Vektor::metode3(Vektor v){ return v; } */ Vektor& Vektor::metode4(Vektor& v){ return v; } Vektor* Vektor::metode5(Vektor& v){ Vektor *p = new Vektor(v); return p; } main.cpp #include <iostream> #include "vektor.h" using std::cout; using std::endl; void main() { { Vektor a(1,5), b(1,5), c(1,5); a = b + c + b; } cout << "Slutt på programmet." << endl; system("PAUSE"); } Console Spesial konstruktør. Nr: 1 Spesial konstruktør. Nr: 2 Spesial konstruktør. Nr: 3 Operator+ Kopikonstruktør. Nr: 4 Kopikonstruktør. Nr: 5 Destruktør. Nr: 4 Operator+ Kopikonstruktør. Nr: 6 Kopikonstruktør. Nr: 7 Destruktør. Nr: 6 Tildelingsoperator Destruktør. Nr: 7 Destruktør. Nr: 5 Destruktør. Nr: 3 Destruktør. Nr: 2 Destruktør. Nr: 1 Slutt på programmet. Press any key to continue . . . Lenke til kommentar
zotbar1234 Skrevet 1. oktober 2010 Del Skrevet 1. oktober 2010 (endret) Står litt fast her, så trenger litt hjelp. Skal forklare hva som skjer når jeg kjører kodesnutten i main.cpp. Forstår deler av det. Hvorfor blir kopikonstruktøren kallet 4 ganger? Høyst sannsynlig fordi kompilatoren er litt slapp på å optimalisere vekk objektene som returneres. Hvorfor blir to av dem fjernet av destruktøren med en gang, mens de to andre blir fjernet etter {} ? Etter? ITYM "før" (det er faktisk et krav). Vektor Vektor::operator+(const Vektor& v) const{ cout << "Operator+" << endl; Vektor temp(*this); for (int i = 0; i < ant; i++){ temp.p[i] += v.p[i]; } return temp; } Dette er den interessante delen 1 -- det er to kall på copy ctor her i den naive implementasjonen: en for å lage temp, og en for å lage returverdien. { Vektor a(1,5), b(1,5), c(1,5); a = b + c + b; } Alle copy ctors blir kalt i det aritmetiske uttrykket. Koden er ekvivalent med: Vektor tmp1(operator+(b, c)); // 2 copy ctors (1 for temp, 1 for tmp1) Vektor tmp2(operator+(tmp1, b)); // 2 copy ctors (1 for temp, 1 for tmp2) operator=(a, tmp2); Langt i fra alle kompilatorer gjør 4 copy ctor kall (icc og gcc gjør ikke det, clang++ gjør det, iallfall blant de jeg kan sjekke kvikt). edit: trykkfeil Endret 1. oktober 2010 av zotbar1234 Lenke til kommentar
Leif.ross Skrevet 3. oktober 2010 Del Skrevet 3. oktober 2010 hei, driver å fikler litt med opengl igjen og prøver å lage en liten kodesnutt for å rotere via tastaturet, kompilerer helt fint, men det skjer ikke noe når jeg trykker. liten snutt her, kan paste hele koden viss det hjelper. void handleKeyPress (unsigned char key, int x, int y) { //mouse pos switch (key) { case 27: //escape key exit(0); } switch (key) { case 65:// tror dette er A _rotate+=1.0f; }; } Lenke til kommentar
hallgeirl Skrevet 4. oktober 2010 Del Skrevet 4. oktober 2010 (endret) hei, driver å fikler litt med opengl igjen og prøver å lage en liten kodesnutt for å rotere via tastaturet, kompilerer helt fint, men det skjer ikke noe når jeg trykker. liten snutt her, kan paste hele koden viss det hjelper. void handleKeyPress (unsigned char key, int x, int y) { //mouse pos switch (key) { case 27: //escape key exit(0); } switch (key) { case 65:// tror dette er A _rotate+=1.0f; }; } Jeg regner med det er Glut du bruker for input (i og med at du bruker OpenGL og du ikke nevner noe annet)? Isåfall må keypress-funksjonen din registreres som en callback-funksjon ved hjelp av funksjonen glutKeyboardFunc ( http://www.opengl.org/resources/libraries/glut/spec3/node49.html#SECTION00084000000000000000 ). Forresten, hvorfor har du 2 switch-er? Skal du ha en switch per condition er jo hele poenget borte vekk switch(blabla){ case 5: foo(); break; case 6: bar(); break; default: applejuice(); } Endret 4. oktober 2010 av hallgeirl Lenke til kommentar
Ståle Skrevet 10. oktober 2010 Del Skrevet 10. oktober 2010 (endret) Hvis jeg lager en pointer i main, og gir den til 2 forskjellige klasser. Og så vil slette pointeren ifra en av klassene, slik at den blir slettet hos begge. Hvordan går jeg fram da? Hvis jeg sletter den i den ene klassen, blir det seg fault når jeg prøver å slette den samme i andre klassen. Endret 10. oktober 2010 av Ståle Lenke til kommentar
zotbar1234 Skrevet 10. oktober 2010 Del Skrevet 10. oktober 2010 Hvis jeg lager en pointer i main, og gir den til 2 forskjellige klasser. Og så vil slette pointeren ifra en av klassene, slik at den blir slettet hos begge. Hvordan går jeg fram da? Kan du lage den minste kodesnutten som illustrerer problemet? Hvis jeg sletter den i den ene klassen, blir det seg fault når jeg prøver å slette den samme i andre klassen Hvis du allokerer et objekt dynamisk vha new/new[]/malloc, så skal det objektet slettes nøyaktig en gang vha delete/delete[]/free. Lenke til kommentar
Ståle Skrevet 10. oktober 2010 Del Skrevet 10. oktober 2010 (endret) class A { Asd* internPtr; settInternPtr( Asd* ); } A* enA = new A(); A* toA = new A(); Asd* test = new Asd(); enA->settInternPtr( test ); toA->settInternPtr( test ); Det blir ihvertfall feil når jeg gjør sånn, men funker hvis jeg lager en kopi og sender til #2. Endret 10. oktober 2010 av Ståle Lenke til kommentar
zotbar1234 Skrevet 10. oktober 2010 Del Skrevet 10. oktober 2010 (endret) class A { Asd* internPtr; settInternPtr( Asd* ); } A* enA = new A(); A* toA = new A(); Asd* test = new Asd(); enA->settInternPtr( test ); toA->settInternPtr( test ); Når du gjør en "delete internPtr;" i en metode kalt for enA eller toA, så _er_ det objektet slettet. Du trenger ikke å slette det en gang til. Det du kanskje er interessert i er hvordan man kan si "delete internPtr;" i enA/toA uten å bry seg om den andre har allerede foretatt en sletting? Dersom det test peker på ikke er sirkulært er den enkleste løsningen boost::shared_ptr. Endret 10. oktober 2010 av zotbar1234 1 Lenke til kommentar
Vademecum Skrevet 2. november 2010 Del Skrevet 2. november 2010 Leker meg litt med C++. Jeg har brukt http://www.cprogramming.com/tutorial.html#c++tutorial og nettopp kommet forbi arrays, men lurte litt på et program jeg lagde tidligere. Hvis du velger noe annet enn 'bool' går den helt bananas, hvordan kan jeg løse dette på en bedre måte? #include <iostream> using namespace std; int main() { for (;{ bool unit; double degree; cout<<"Starting unit: Celsius(0) or Fahrenheit(1)?\n"; cin>> unit; cin.ignore(); if (unit==true) { cout<<"You picked Fahrenheit\nAdd degrees: "; cin>> degree; cin.ignore(); cout<< (degree-32)*5/9 <<" Celsius"; } else { cout<<"You picked Celsius\nAdd degrees: "; cin>> degree; cin.ignore(); cout<< degree*9/5+32 <<" Fahrenheit"; } cin.get(); } } Som du kanskje ser så prøvde jeg ut 'for'. Legger ved en annen kodesnutt i slengen som har samme problem (hvis du velger noe annet enn 'int'). #include <iostream> using namespace std; int main() { int input; do { cout<<"1. Door one\n"; cout<<"2. Door two\n"; cout<<"3. Door three\n"; cout<<"4. Exit\n"; cout<<"Selection: "; cin>> input; switch ( input ) { case 1: cout<<"\nOne\n\n"; break; case 2: cout<<"\nTwo\n\n"; break; case 3: cout<<"\nThree\n\n"; break; case 4: cout<<"\nThank you for playing\n\n"; break; default: cout<<"\nError, bad input\n\n"; break; } }while (input!=4); } Kom gjerne med konstruktiv kritikk, jeg har aldri kodet før så hvis det er mye tull; skrik ut. Lenke til kommentar
Thomas. Skrevet 6. desember 2010 Del Skrevet 6. desember 2010 Ja, da har jeg fått til et vindu (GUI). Men, so what? Hvordan kan man opprette tekst/bokser/knapper/lage funksjoner i dette vinduet? Har prøvd litt med cout, printf også videre uten å lykkes Jeg har brukt koden som er tilgjenglig her: http://www.winprog.org/tutorial/ (Download Full Example Code) Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå