Hejsan! Spontant så ska det väl åtminstone vara Det går inte. Felet blir: Pröva att casta print(): Alternativt så bör det gå med något i stil med <b>Det är nog att betrakta som en något snyggare lösning.</b> Det gick fungerade också, print<std::string>! Vänta nu, säg om det där... mm.. skrev visst fel. Skrev sist nog bara "(void(*)(const std::string &))print" nu när jag tänker efter! Denna kod fungerar: Varför överhuvudtaget hålla på med c funktioner i STL. Eftersom funktioner har en direkt motsvarighet i funktionella språk. >Man kan vända på det, varför använda funktionsobjekt? <b>>Typsäkerhet och ett enhetligt sätt oavsett hur vilka argument funktionen har.</b> <b>Vilket värde får parameter 2?</b> Värde för parameter 2 blir 1 om inget annat anges, jag skrev ju: >Värde för parameter 2 blir 1 om inget annat anges, jag skrev ju: Om jag har förstått rätt skapas två funktioner när man anger defaultvärde för ett argument: Njae, kan det där verkligen stämma? 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: 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. Intressant. Jag skulle tro att det är en bugg i den kompilator du använder (VC++)? Har kikat lite på det nu, och default-argumentet verkar funka oavsett vilken variant man använder i MinGW (gcc). 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. 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". Ja, precis som för inline:ade virtuella metoder. Mycket möjligt. Jag skulle säga att det är ganska klart att det inte skall fungera och således är en bugg i VC++. <b>>Jag skulle säga att det är ganska klart att det inte skall fungera och således är en bugg i VC++.</b>anropa funktionsmall i en for_each sats!
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!Sv: anropa funktionsmall i en for_each sats!
<code>
for_each(vec.begin(),vec.end(),&print);
</code>Sv:anropa funktionsmall i en for_each sats!
<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>Sv: anropa funktionsmall i en for_each sats!
<code>
for_each(vec.begin(),vec.end(),(void(*)(const std::string &))print);
</code>Sv: anropa funktionsmall i en for_each sats!
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. Sv:anropa funktionsmall i en for_each sats!
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.Sv:anropa funktionsmall i en for_each sats!
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!Sv: anropa funktionsmall i en for_each sats!
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.Sv:anropa funktionsmall i en for_each sats!
<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? Sv: anropa funktionsmall i en for_each sats!
Använd funktionsobjekt istället.Sv:anropa funktionsmall i en for_each sats!
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.Sv: anropa funktionsmall i en for_each sats!
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.Sv:anropa funktionsmall i en for_each sats!
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.Sv:anropa funktionsmall i en for_each sats!
Antagligen odefinierat så att om i hade skrivits ut skulle allsköns underliga värden visas.Sv:anropa funktionsmall i en for_each sats!
<code>
template <typename X> void print(const X & a, int i = 1) //int i = 1
{
std::cout << a;
}
</code>Sv: anropa funktionsmall i en for_each sats!
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>Sv: anropa funktionsmall i en for_each sats!
<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.Sv:anropa funktionsmall i en for_each sats!
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å?).
Sv:anropa funktionsmall i en for_each sats!
<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".Sv: anropa funktionsmall i en for_each sats!
Men prova att köra med det första förslaget, med casting, vad händer då?Sv: anropa funktionsmall i en for_each sats!
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.Sv:anropa funktionsmall i en for_each sats!
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.Sv: anropa funktionsmall i en for_each sats!
Sv: anropa funktionsmall i en for_each sats!
Sv:anropa funktionsmall i en for_each sats!
Sv: anropa funktionsmall i en for_each sats!
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).Sv:anropa funktionsmall i en for_each sats!
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.