Fetstil Fetstil Kursiv Understrykning linje färgläggning tabellverk Punktlista Nummerlista Vänster Centrerat högerställt Utfyllt Länk Bild htmlmode
  • Forum & Blog
    • Forum - översikt
      • .Net
        • asp.net generellt
        • c#
        • vb.net
        • f#
        • silverlight
        • microsoft surface
        • visual studio .net
      • databaser
        • sql-server
        • databaser
        • access
        • mysql
      • mjukvara klient
        • datorer och komponenter
        • nätverk, lan/wan
        • operativsystem
        • programvaror
        • säkerhet, inställningar
        • windows server
        • allmänt
        • crystal reports
        • exchange/outlook
        • microsoft office
      • mjukvara server
        • active directory
        • biztalk
        • exchange
        • linux
        • sharepoint
        • webbservers
        • sql server
      • appar (win/mobil)
      • programspråk
        • c++
        • delphi
        • java
        • quick basic
        • visual basic
      • scripting
        • asp 3.0
        • flash actionscript
        • html css
        • javascript
        • php
        • regular expresssion
        • xml
      • spel och grafik
        • DirectX
        • Spel och grafik
      • ledning
        • Arkitektur
        • Systemutveckling
        • krav och test
        • projektledning
        • ledningsfrågor
      • vb-sektioner
        • activeX
        • windows api
        • elektronik
        • internet
        • komponenter
        • nätverk
        • operativsystem
      • övriga forum
        • arbete karriär
        • erbjuda uppdrag och tjänster
        • juridiska frågor
        • köp och sälj
        • matematik och fysik
        • intern information
        • skrivklåda
        • webb-operatörer
    • Posta inlägg i forumet
    • Chatta med andra
  • Konto
    • Medlemssida
    • Byta lösenord
    • Bli bonsumedlem
    • iMail
  • Material
    • Tips & tricks
    • Artiklar
    • Programarkiv
  • JOBB
  • Student
    • Studentlicenser
  • KONTAKT
    • Om pellesoft
    • Grundare
    • Kontakta oss
    • Annonsering
    • Partners
    • Felanmälan
  • Logga in

Hem / Forum översikt / inlägg

Posta nytt inlägg


anropa funktionsmall i en for_each sats!

Postades av 2008-01-05 18:09:56 - Fredrik Olofsson, i forum c++, Tråden har 29 Kommentarer och lästs av 2039 personer

Hejsan!
Jag har en funktion mall som ser ut såhär:
<code>
template <typename X> void print(const X & a)
{
std::cout << a;
}
</code>

Men jag kan inte använda den i en for_each sats:
<code>
std::vector<std::string> vec;
vec.push_back("Hejsan");
vec.push_back("hur");
vec.push_back("är");
vec.push_back("läget");
for_each(vec.begin(),vec.end(),print);
</code>

Hur ska jag kunna göra för att for_each ska anropa min funktionsmall?

Tack på förhand!


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-05 18:24:58 - Niklas Jansson

Spontant så ska det väl åtminstone vara

<code>
for_each(vec.begin(),vec.end(),&print);
</code>


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-05 18:56:32 - Fredrik Olofsson

Det går inte. Felet blir:
<code>
error: no matching function for call to ‘for_each(__gnu_cxx::__normal_iterator<std::basic_string<char, std::char_traits<char>,
std::allocator<char> >*, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >,
std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >,
__gnu_cxx::__normal_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> >*,
std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char,
std::char_traits<char>, std::allocator<char> > > > >, <unresolved overloaded function type>)’
</code>


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-05 19:05:29 - Per Persson

Pröva att casta print():
<code>
for_each(vec.begin(),vec.end(),(void(*)(const std::string &))print);
</code>


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-05 19:18:20 - Fredrik Olofsson

Det gick., Tack Per!


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-06 13:31:42 - Niklas Jansson

Alternativt så bör det gå med något i stil med

for_each(vec.begin(),vec.end(),print<const std::string &>);

S.k. "Template specialization".
Det är nog att betrakta som en något snyggare lösning. Prova att lägga till ett argument på print och kolla om du får kompileringsfel eller kompileringsvarning.


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-06 15:58:07 - Per Persson

<b>Det är nog att betrakta som en något snyggare lösning.</b>

Håller med. Fast jag tror att det bara skall vara print<std::string> eftersom det är T som skall anges, inte typen på hela argumentet.


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-06 22:39:49 - Niklas Jansson

Jepp, korrekt. Som sagt, "något i stil med".


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-07 02:19:37 - Fredrik Olofsson

Det gick fungerade också, print<std::string>!

Provade som du sa Niklas att lägga till ett argument på print och då fick jag kompilerings fel, när jag använde cast metoden. Dock inte när jag skrev print<std::string>.

Tack!


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-07 12:04:01 - Niklas Jansson

Vänta nu, säg om det där...

När du C-castade fick du fel, men inte när du gjorde template-specialisering?
Det borde vara så att när du castar så får du en varning, men definitivt ett kompileringsfel när du gör en template-specialisering.


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-08 00:58:01 - Fredrik Olofsson

mm.. skrev visst fel. Skrev sist nog bara "(void(*)(const std::string &))print" nu när jag tänker efter! Denna kod fungerar:
<code>
template <typename X> void print(const X & a, int i=1)
{
std::cout << a << std::endl;
}

int main(int argc, char *argv[])
{
std::vector<std::string> ve;
ve.push_back("Hejsan");
ve.push_back("på");
ve.push_back("dig");
for_each(ve.begin(),ve.end(),(void(*)(const std::string &,int))print);
for_each(ve.begin(),ve.end(),print<std::string>);
return 0;
}
</code>

Eller hur menar du Niklas i så fall?


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-08 08:19:02 - Martin Adrian

Varför överhuvudtaget hålla på med c funktioner i STL.

Använd funktionsobjekt istället.


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-08 09:54:17 - Niklas Jansson

Eftersom funktioner har en direkt motsvarighet i funktionella språk.

Man kan vända på det, varför använda funktionsobjekt?
Du behöver skriva en klass för varje enskild funktion du vill implementera, och på något sätt instansiera objektet varje gång du behöver den.

Missförstå mig inte, funktionsobjekt är bra, men ska inte överanvändas. Mer och mer i C++-communityn går mot metaprogrammering, lambdafunktioner osv.

Mindre mängd kod är nästan alltid bra, och vanliga funktioner ger mindre mängd kod i det här fallet.


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-08 11:31:35 - Martin Adrian

>Man kan vända på det, varför använda funktionsobjekt?

Typsäkerhet och ett enhetligt sätt oavsett hur vilka argument funktionen har.

Jag förstår inte alls hur koden ovan kan fungera. Funktionens signatur är
void(*)(const std::string &,int) vilket knappast kan skickas till for_each. Vilket värde får parameter 2?

Med funktionsobjekt hade det blivit

for_each(..., bind(print<std::string>,_1,1))

>Du behöver skriva en klass för varje enskild funktion du vill implementera, och på något sätt
>instansiera objektet varje gång du behöver den.

Har jag aldrig gjort. function, bind och lambda fixar det enkelt.


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-08 13:50:33 - Niklas Jansson

<b>>Typsäkerhet och ett enhetligt sätt oavsett hur vilka argument funktionen har.</b>
Mot detta hade jag argumenterat med något i stil med att "Det blir precis lika typsäkert med funktioner; funktionsobjekt och 'funktionsobjektstemplates' skapades just för att vanliga funktioner skulle vara ekvivalenta.".
Tills jag såg den skumma koden.

<b>>Jag förstår inte alls hur koden ovan kan fungera. Funktionens signatur är
void(*)(const std::string &,int) vilket knappast kan skickas till for_each. Vilket värde får parameter 2?</b>
Exakt, och trots att jag inte har tid har jag nu blivit så pass intresserad att jag kanske ska gå in och kolla noggrannare på det här.

<b>>>Du behöver skriva en klass för varje enskild funktion du vill implementera, och på något sätt
>>instansiera objektet varje gång du behöver den.
>Har jag aldrig gjort. function, bind och lambda fixar det enkelt.</b>
Good point. Jag får väl försöka försvara mig med att jag bara har gått in i boost precis till de grejerna jag har behövt så att säga.


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-08 22:50:55 - Per Persson

<b>Vilket värde får parameter 2?</b>

Antagligen odefinierat så att om i hade skrivits ut skulle allsköns underliga värden visas.


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-09 00:23:31 - Fredrik Olofsson

Värde för parameter 2 blir 1 om inget annat anges, jag skrev ju:
<code>
template <typename X> void print(const X & a, int i = 1) //int i = 1
{
std::cout << a;
}
</code>


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-09 08:29:56 - Martin Adrian

>Värde för parameter 2 blir 1 om inget annat anges, jag skrev ju:

Nix.

Defaultparametrar sätts av den som anropar funktionen.

dvs. print("abc") översätts av kompilatorn till print("abc",1) före anropet.

Om du anropar via en funktionspekare vet inte kompilatorn vilken funktion som anropas.

<code c++>
void func1(int a = 1) { cout << a; }
void func2(int a = 2) { cout << a; }

void anropafunc(void (*funcptr)(int)) {
funcptr(); // hur skall den här funktionen veta om defaultparametern skall vara 1 eller 2
}

int main() {
anropafunc(func1);
anropafunc(func2);
}
<code>


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-09 15:04:26 - Per Persson

Om jag har förstått rätt skapas två funktioner när man anger defaultvärde för ett argument:
<code>
void print_1(std::string &a)
{
print_1(s, 1);
}

void print_2(std::string &a, int i)
{
std::cout << a;
}
</code>
Om print() anropas med två argument används i själva verket print_2(), medan om den anropas med ett argument används print_1().

När du kör med
<code>for_each(ve.begin(),ve.end(),(void(*)(const std::string &,int))print);</code>
ser kompilatorn att funktionen skall ha två argument och väljer därför print_2() men då inget andra argument skickas med av for_each() kan heltalet få vilket värde som helst.

Om du däremot kör med
<code>for_each(ve.begin(),ve.end(),(void(*)(const std::string &))print);</code>
ser kompilatorn att funktionen skall ha ett argument och väljer därför print_1() som i sin tur anropar print_2() med andra argumentet satt till 1.


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-09 15:12:58 - Niklas Jansson

Njae, kan det där verkligen stämma?

Jag är tämligen säker på att det bara är syntaktiskt socker:

void f(int a, int b=0)
{
 ...
}

...
f(5, 5);
f(5); // samma anrop som f(5,0);


I synnerhet eftersom default-värden måste anges i deklarationen om den ska funka (det är väl så?).


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-09 15:46:32 - Fredrik Olofsson

Kanske för du går 2 steg och kompilatorn kollar bara ett. Men jag vet inte, men ett faktum är att denna kod går att kompilera:
<code>
#include <string>
#include <iostream>
#include <vector>

template <typename X> void print(const X & a, int i=99);

int main(int argc,char *argv[])
{
std::vector<std::string> ve;
ve.push_back("i");
for_each(ve.begin(),ve.end(),print<std::string>);
std::cout << std::endl;
return 0;
}


template <typename X> void print(const X & a, int i)
{
std::cout << a << "->" << i;
}
</code>
och den skriver ut "i->99".


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-09 16:45:37 - Niklas Jansson

Det kan jag köpa, eftersom du använder template specialization. Då omvandlas det i kompileringen till ett anrop som automatiskt tar ett default-argument.

Men prova att köra med det första förslaget, med casting, vad händer då?


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-09 17:23:46 - Martin Adrian

Intressant. Jag skulle tro att det är en bugg i den kompilator du använder (VC++)?

Koden bör inte fungera(*)

Jag testade med Comeau online och med
<code>template <typename X> void print(const X & a, int i=99);</code>

får jag "internal error"!

medan med
<code>void print(const std::string& a, int i = 99);</code>
(dvs ej template)

får jag "too few arguments in call".

----
Anledningen till att det inte bör fungera är att om du har två likadana funktioner med olika default skall de kunna använda samma instans av for_each funktionen.

<code>
template <typename X> void print1(const X & a, int i=99);
template <typename X> void print2(const X & a, int i=50);

...

for_each(ve.begin(),ve.end(),print1<std::string>);
for_each(ve.begin(),ve.end(),print2<std::string>);

</code>

Svårt att testa eftersom troligen både inlining och templates spelar roll.


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-09 19:17:15 - Niklas Jansson

Har kikat lite på det nu, och default-argumentet verkar funka oavsett vilken variant man använder i MinGW (gcc).

Att det fungerar i fallet med cast är ju helt vansinnigt. En kandidat till förklaring blir ju Pers.
Men jag måste säga att jag har svårt att se Pers variant som tänkbar. Objekten kan ju behöva kopieras, och potentiellt får programmet olika betydelse beroende på om man använder default eller inte.


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-09 19:57:34 - Niklas Jansson

Förresten, så här kan det vara. Anledningen till att det funkar med cast skulle kunna vara att kompilatorn fortfarande har koll på funktionen, man kan ju inte ändra funktionssignaturen, annat än just att specialisera m a p templates, enligt de varianterna jag provade. I så fall sätts helt enkelt funktionsanropet in, default-parametern används, och allt är frid och fröjd.


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-09 21:02:05 - Per Persson

Du har nog rätt, Niklas. När du nu säger det har jag nog sett då jag kompilerat till assembly att defaultvärdet läggs på stacken direkt. Å andra sidan skulle man kunna tänka sig att båda sakerna sker, dvs att det skapas en extra funktion, men att den oftast "inlineas".


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-09 22:45:23 - Niklas Jansson

Ja, precis som för inline:ade virtuella metoder. Mycket möjligt.


Svara

Sv: anropa funktionsmall i en for_each sats!

Postades av 2008-01-10 09:25:15 - Martin Adrian

Jag skulle säga att det är ganska klart att det inte skall fungera och således är en bugg i VC++.

Anledningen till att det inte skall fungera är att anropet till funktionen (inuti for_each) görs med hjälp av en pekare till funktionen.

<code>
void (*ptr)(const std::string&, int); // dvs en pekare till en funktion med två argument

ptr("abc");
</code>

Ovanstående kod kompilerar naturligtvis inte.

Vad som har hänt i det här fallet är att eftersom kompilatorn vet vilken funktion som pekaren pekar på så har den gjort om anropet till att inte längre gå via pekaren utan direkt. En sådan optimering är tillåten men den får inte förändra programmets funktion.

Jag skall försöka formulera ett inlägg på comp.std.c++ och se vad de säger där.

>Ja, precis som för inline:ade virtuella metoder. Mycket möjligt.

Finns ingen final/sealed i c++ så virituella metoder kan inte bli inlinade (förutom i en konstruktor).


Svara

Sv:anropa funktionsmall i en for_each sats!

Postades av 2008-01-10 11:17:37 - Niklas Jansson

<b>>Jag skulle säga att det är ganska klart att det inte skall fungera och således är en bugg i VC++.</b>
Och också i gcc, en tämligen erkänt bra kompilator...

<b>>Finns ingen final/sealed i c++ så virituella metoder kan inte bli inlinade (förutom i en konstruktor).</b>
En kompilator får mycket väl inlina virtuella metoder. Ofta går det inte, men i ett fall säg:

class A
{
public:
  virtual void f(void);
} ;

...
A a;
a.f(); //kan inlinas

Däremot sker det ju förstås i stort sett aldrig annars.


Svara

Nyligen

  • 19:38 Rekommendera något intressant
  • 19:13 Международная перевозка грузов
  • 00:01 DL Van Tuning | Exclusive Body Kit
  • 12:08 Indian casino
  • 04:14 Vad finns det för kratomalternativ
  • 14:16 Indian online casino
  • 14:15 Indian online casino
  • 08:28 Butiksskyltar: Hur upplever utbude

Sidor

  • Hem
  • Bli bonusmedlem
  • Läs artiklar
  • Chatta med andra
  • Sök och erbjud jobb
  • Kontakta oss
  • Studentlicenser
  • Skriv en artikel

Statistik

Antal besökare:
Antal medlemmar:
Antal inlägg:
Online:
På chatten:
4 570 873
27 965
271 770
508
0

Kontakta oss

Frågor runt konsultation, rådgivning, uppdrag, rekrytering, annonsering och övriga ärenden. Ring: 0730-88 22 24 | pelle@pellesoft.se

© 1986-2013 PelleSoft AB. Last Build 4.1.7169.18070 (2019-08-18 10:02:21) 4.0.30319.42000
  • Om
  • Kontakta
  • Regler
  • Cookies