wäre möglich, um z.B. zwischen fkt(x) und fkt(5) zu unterscheiden. So
könnte man einen optimierten Algorithmus für den fkt(5)-Fall schreiben.
Aber Compiler sagt nein.
Kann mir jemand erklären, warum das nicht erlaubt ist? Wo würde das zu
Problemen führen?
Zur not könnte man das (in c++) mit templates lösen. Aber weiß trotzdem
wer, wie man das mit echter Überladung macht?
Danke schon mal,
Phlupp
Dein const uint8_t sagt nur das du einen uint8_t der Funktion übergibst
der in der Funktion nicht verändert werden darf/kann.
Es heißt nicht, dass die Funktion einen const uint8_t erwartet.
>Es heißt nicht, dass die Funktion einen const uint8_t erwartet.
Das meint auch der Compiler. Ich frage mich nur, warum. Wo wäre das
Problem?
>Du möchtest constexpr:
"a parameter cannot be declared 'constexpr'"
..Und die komplette Funktion auch nicht, da es eigentlich eine
Phlupp schrieb:> Kann mir jemand erklären, warum das nicht erlaubt ist?
Es ergibt sich einfach daraus, dass Parameter per Kopie übergeben
werden. Wenn du eine Funktion hast, wie
> void fkt(const uint8_t);
dann wird das übergebene Argument in den Parameter kopiert. Der ist dann
im Prinzip quasi eine lokale Variable, die vom Aufrufer initialisiert
wurde. Ob die dann innerhalb der Funktion const ist oder nicht, ist aber
dem Aufrufer egal.
Wenn du jetzt keine Überladungen hast, sondern nur diese eine Funktion,
erwartest du dann, dass du die nur mit Konstanten als Argument aufrufen
kannst?
PPB schrieb:> Das ist C++ und nicht C.
Hat ja auch keiner behauptet, dass das C sei.
probiert.
2(a), 2b und 2c sind identisch. (Was ich bei b und c genau mache, weiß
ich ehrlich gesagt nicht genau..)
Es scheint aber so, als wäre fkt3() noch immer am besten optimierbar vom
compiler.
Warum?
Gibt es denn keine Möglichkeit, eine Funktion-Überladung (mit 2 'echten'
Args) zu erhalten, die sich wie ein Template verhält, was das angeht?!
Jetzt, da
1
fkt1(T y, uint8_t & x);
2
fkt2(T y, const uint8_t & x);
funktioniert, frage ich mich eigentlich um so mehr, warum
1
fkt1(T y, uint8_t x);
2
fkt2(T y, const uint8_t x);
nicht funktioniert, obwohl es dafür keine Notwendigkeit zu geben
scheint.
...denn im asm wird x eh nicht unterschiedlich behandelt, egal ob "&"
oder nicht..
Phlupp schrieb:> Jetzt, da fkt1(T y, uint8_t & x);> fkt2(T y, const uint8_t & x);>> funktioniert, frage ich mich eigentlich um so mehr, warumfkt1(T y,> uint8_t x);> fkt2(T y, const uint8_t x);>> nicht funktioniert, obwohl es dafür keine Notwendigkeit zu geben> scheint.
Das hat rmagnus schon gut erklärt. Der Unterschied bei der ersten
Funktion ist, dass man eine Referenz übergibt. Ist die Variable die man
dabei übergibt konstant, dann kann man die nur als const& übergeben. Bei
der Kopie ist const für den Aufrufer irrelevant. Wenn die beiden
Funktionen etwas anderes tun sollen, warum gibt man denen dann nicht
einfach unterschiedliche Namen?
Willst du über den Unterschied philosophieren oder hast du ein konkretes
Problem?
Danke,
ich hatte die Hoffnung, es gäbe eine schöne Lösung.
>Wenn die beiden>Funktionen etwas anderes tun sollen, warum gibt man denen dann nicht>einfach unterschiedliche Namen?
Weil sie eigentlich das gleiche tun, nur auf unterschiedliche Weise,
bzw. mit leicht unterschiedlichen Typen.
Deine Frage könnte man auch übersetzen mit:"Warum gibt es überhaupt
Überladung?"
>Willst du über den Unterschied philosophieren oder hast du ein konkretes>Problem?
Für das konkrete Problem, siehe Eingangspost. Philosophieren würde ich
eher darüber, warum man/der Compiler nicht unterscheidet, obwohl er es
könnte. Es spricht schließlich nichts dagegen, es auf die 'allgemeinere'
Variante zurückzuführen, sollte nur eine existieren. So wie es jetzt
ist, bin ich offenbar gezwungen auf Templates auszuweichen, was den von
dir geforderten unterschiedlichen Namen schon recht nahe kommt (bzw. es
genau genommen ist).
Phlupp schrieb:> Deine Frage könnte man auch übersetzen mit:"Warum gibt es überhaupt> Überladung?"
Für mich ist Überladung sinnvoll, wenn die gleiche logische Operation
(Funktionsname) auf verschiedenen Datentypen ausgeführt werden kann,
dazu aber unterschiedliche Implementierung nötig sind. Ob die in der
Funktion verwendete Kopie const ist oder nicht ändert aber nichts am
Typ.
Phlupp schrieb:> Für das konkrete Problem, siehe Eingangspost.
Ich habe deinen Post gelesen.
Du hast ein Problem konstruiert, welches mir in der praktischen
Anwendung von C++ noch nie begegnet ist. Deshalb habe ich nach einem
konkreten Problem gefragt, dass du lösen möchtest. Vielleicht kannst du
mal ein konkretes Beispiel posten, dann kann man dir vielleicht auch
helfen.
Working draft N4659 S.313
"Parameter declarations that differ only in the presence or absence of
const and/or volatile are equivalent. That is, the const and volatile
type-specifiers for each parameter type are ignored."
Phlupp schrieb:> Für das konkrete Problem, siehe Eingangspost.
Da sehe ich kein Problem. Höchstens den Versuch, es zu lösen. Wofür du
glaubst, zwei Überladungen für const und nicht-const zu brauchen, geht
aus dem Posting nicht hervor. Genau wie mkbit habe ich sowas noch nie
gebraucht und auch keine Idee, wofür man es brauchen könnte.
Phlupp schrieb:> Philosophieren würde ich eher darüber, warum man/der Compiler nicht> unterscheidet, obwohl er es könnte.
Das hab ich bereits geschrieben. Die "constness" von dem, was du
übergibst, hat nichts mit der der Funktionsparameter zu tun.
Rolf M. schrieb:> Genau wie mkbit habe ich sowas noch nie> gebraucht und auch keine Idee, wofür man es brauchen könnte.
Geht mir auch so!
Wofür brauchst du sowas?
Hmmm ..
void fiction( somewhat unsigned_integer V )
{
const V = 5;
/* do code here */
}
???
Bin kein C-Coder , hacke aber ab und an in Open Source Quellen herum
....
Das "const" bezieht sich nur auf die erlaubte Verwendung der Variable
innerhalb der Funktion und nicht auf das was du übergeben willst.
1
voidfoo(intx)
2
{
3
while(x>0)
4
{
5
--x;
6
}
7
}
8
9
...main...
10
{
11
foo(5);
12
13
intx=5;
14
foo(x);
15
printf("%d",x);// und jetzt darüber wundern das x immernoch 5 ist:-)
16
17
constintx2=5;
18
foo(x2);
19
}
So, und jetzt versuch das mal mit const...
Da wird der Compiler dir ganz schnell die Freundschaft kündigen und das
sogar ganz egal ob du das mit einer Konstante oder einer Variable
aufrufst. Die Fehlermeldung kommt ganz wo anders zustande.
Da kann ich nur sagen, man soll nicht immer von sich auf andere
schließen..
Wie wäre es z.B. konkret mit dem Zählen gesetzter Bits im Byte (was
einfacheres fällt mir gerade nicht ein). Ist das Byte bekannt zur
Compile-Zeit, kann man im Extremfall die Berechnung ganz weg lassen
(0x00). Ist die Var unbekannt, muss man alle 8 Stellen beachten - das
ist ...uNeNdLiCh-mal soviel...
>"Parameter declarations that differ only in the presence or absence of>const and/or volatile are equivalent. That is, the const and volatile>type-specifiers for each parameter type are ignored."
Steht da zufällig auch, warum man das für eine gute Idee gehalten hat?
Ignorieren hätte man es auch erst dann können, wenn es nicht mehr anders
geht.
Phlupp schrieb:> Steht da zufällig auch, warum man das für eine gute Idee gehalten hat?> Ignorieren hätte man es auch erst dann können, wenn es nicht mehr anders> geht.
Das const im Funktionsparameter ist lediglich eine lokale Deklaration
als konstant. De Facto handelt es sich nach außen hin um exakt den
gleichen Datentyp wie ohne const. Die Tatsache dass du versuchst hier zu
überladen zeigt nur, dass du das auch nach etlichen Erklärungen nicht
verstanden hast.
Die Frage ist nicht, warum man sich dazu entschieden hat const im
Fkt-Kopf zu ignorieren, sondern warum man es beachten sollte. Es
dahingehend zu ignorieren ist nur folgerichtig anhand der Bedeutung die
es dort hat.
Phlupp schrieb:> Da kann ich nur sagen, man soll nicht immer von sich auf andere> schließen..
Man sollte anderen eine Glaskugel schenken, wenn sie einen verstehen
sollen was man denkt. Ganz im ernst, du regst dich hier über etwas für
die meisten hier unnötiges auf, hältst es aber nicht für notwendig und
zu helfen, deine Gedanken nachvollziehen zu können.
Phlupp schrieb:> Wie wäre es z.B. konkret mit dem Zählen gesetzter Bits im Byte (was> einfacheres fällt mir gerade nicht ein). Ist das Byte bekannt zur> Compile-Zeit, kann man im Extremfall die Berechnung ganz weg lassen> (0x00). Ist die Var unbekannt, muss man alle 8 Stellen beachten - das> ist ...uNeNdLiCh-mal soviel...
Wie würde das const im Übergabeparameter da weiterhelfen? Const heißt ja
nur, dass die Variable in dem Code nicht verändert werden darf, nicht
dass es eine Compiletimekonstante ist. Aber dafür gibt es ja schon was,
dass du dir sicher angeschaut hast. Tipp: Es fängt mit const an.
Also für mich war die Sache nach
>Danke,>ich hatte die Hoffnung, es gäbe eine schöne Lösung.
erledigt.
Alles weitere ist nur das 'Philosophieren'.
@ Wilma Streit: Und warum glaubst du, dass sich das nach deiner x-ten
Widerholung ändert?! Verwandt mit Anne Fresse? Wenn du dich mit dem
Dogma abfinden möchtest, hält dich keiner auf.
@ M.K. B.: Lies einfach nochmal meinen Eingangspost.. constexpr meinst
du hoffentlich nicht.
>Ganz im ernst, du regst dich hier über etwas für>die meisten hier unnötiges auf, ...
Nach dem Warum fragen und sich Aufregen sind wohl doch leicht
verschiedene Dinge..
>...hältst es aber nicht für notwendig und>zu helfen, deine Gedanken nachvollziehen zu können.
Nun, da ich jetzt ja sogar ein konkretes Beispiel geliefert habe, frage
ich mich wo eine weiterführende Antwort bleibt.. Oder sollte es
letztlich keinen Unterschied machen, ob du eine Glaskugel besitzt oder
nicht?!?
Wie gesagt, im Eingangspost steht eigentlich schon alles (übrigens auch,
dass es mit const nicht geht).
Phlupp schrieb:> Wie gesagt, im Eingangspost steht eigentlich schon alles (übrigens auch,> dass es mit const nicht geht).
Nein!
Da steht nicht was du erreichen möchtest, und vor allen Dingen nicht:
Warum?
Bisher sieht das für mich nach einer fürchterlich dummen Idee aus.
Aber du könntest ja mal sagen, worum es sich wirklich dreht.
Phlupp schrieb:> Da kann ich nur sagen, man soll nicht immer von sich auf andere> schließen..> Wie wäre es z.B. konkret mit dem Zählen gesetzter Bits im Byte (was> einfacheres fällt mir gerade nicht ein). Ist das Byte bekannt zur> Compile-Zeit, kann man im Extremfall die Berechnung ganz weg lassen> (0x00).
Liest du eigentlich, was andere schreiben? const heißt nicht, dass der
Wert zur Compilezeit bekannt ist. Beispiel:
1
#include<stdio.h>
2
voidmyfunc(constintx)
3
{
4
printf("Die 'Konstante' hat den Wert %d\n",x);
5
}
6
7
8
intmain(intargc,char*argv[])
9
{
10
constinti=argc;
11
myfunc(i);
12
return0;
13
}
Das Programm wird (sowohl in C, als auch in C++) problemlos laufen, und
die Werte von i und x sind zur Compilezeit unbekannt. Das const ändert
daran nichts. Das heißt, getrennte Überladungen für const und
nicht-const würden in dem Fall überhaupt nicht helfen.
Und ich verstehe auch nicht, warum man die Berechnung bei zur
Compilezeit bekannten Werten weglassen können soll und was das 0x00
bedeuten soll. Haben alle Compilezeitkonstanten den Wert 0? Oder was
willst du damit sagen?
> Ist die Var unbekannt, muss man alle 8 Stellen beachten - das> ist ...uNeNdLiCh-mal soviel...
Der Funktion ist sie immer unbekannt. Wäre das nicht so, dann bräuchte
man es nicht als Parameter.
>>"Parameter declarations that differ only in the presence or absence of>>const and/or volatile are equivalent. That is, the const and volatile>>type-specifiers for each parameter type are ignored."> Steht da zufällig auch, warum man das für eine gute Idee gehalten hat?
Wie schon mehrfach erwähnt, ergibt sich das automatisch. Wenn man es
anders wöllte, bräuchte man eine zusätzliche Sonderregel für diesen
Fall, durch die das Verhalten anders wäre, als an anderen Stellen. Und
niemand hat das wohl großartig gebraucht, so dass das nicht
gerechtfertigt wäre.
> Ignorieren hätte man es auch erst dann können, wenn es nicht mehr anders> geht.
C++ ist schon kompliziert genug. Da muss man nicht noch zusätzliche
Spezialfälle einbauen, die außer dir keiner zu brauchen scheint.
Phlupp schrieb:> Ist das Byte bekannt zur> Compile-Zeit, kann man im Extremfall die Berechnung ganz weg lassen> (0x00).
Das geht aber nur, wenn die Funktion an der Aufrufstelle expandiert
wird. Die Funktion muß also entweder always_inline oder ein Macro sein.
Phlupp schrieb:> Nun, da ich jetzt ja sogar ein konkretes Beispiel geliefert habe, frage> ich mich wo eine weiterführende Antwort bleibt..
Tut mit leid, ich bin raus. Offensichtlich hast du es nicht nötig, den
freiwilligen Helfern hier entgegen zu kommen.
Es wurde schon n paar Mal erwähnt, aber bei mir hat es damals auch etwas
gedauert...
Das const im parameter erzeugt nicht eine Funktion, der man nur
Konstanten übergeben kann, sondern sie ist ein Versprechen der Funktion,
dass der Parameter nicht verändert wird!
Bei per call by value übergebenen Variablen (nicht Pointer oder
Referenzen) macht es allerdings eh keinen Unterschied..
Phlupp schrieb:> Steht da zufällig auch, warum man das für eine gute Idee gehalten hat?> Ignorieren hätte man es auch erst dann können, wenn es nicht mehr anders> geht.
Ich war noch nicht auf der Welt als function overloading Teil von C++
wurde, aber ich vermute dass man sich aus Gründen der Vernunft dagegen
entschieden hat das const mitspielt.
Man stelle sich folgende Situation vor:
1
voidfkt(constint){
2
cout<<"hier?\n";
3
}
4
5
voidfkt(int){
6
cout<<"oder hier?\n";
7
}
8
9
fkt(5);
Intuitiv wäre dass die const Version mit dem Literal aufgerufen wird.
Weil 5 aber nur vom Typ int ist würde das nie passieren... C++ ist zwar
klassisch die Sprache mit den falschen Defaults, aber das wäre absolut
irre.
PPB schrieb:> Das ist C++ und nicht C.
Interessant, woher beziehst du die Information, dass der TS C verwendet?
Phlupp schrieb:>>Du möchtest constexpr:> "a parameter cannot be declared 'constexpr'"
Tut mir leid, etwas Eigeninitiative kann man wohl doch erwarten.
Phlupp schrieb:> ..dass "const int" ein anderer typ als "int" ist und "5" konstanter als> "a".> Was spräche dagegen?
Gar nix. Du verstehst nur die Sprache nicht, und solltest dir mal ein
gutes C++-Buch zulegen.
Phlupp schrieb:> Philosophieren würde ich> eher darüber, warum man/der Compiler nicht unterscheidet, obwohl er es> könnte. Es spricht schließlich nichts dagegen, es auf die 'allgemeinere'> Variante zurückzuführen, sollte nur eine existieren.Phlupp schrieb:> ich hatte die Hoffnung, es gäbe eine schöne Lösung.
Verwende constexpr, dann macht der Compiler das schon ganz von selbst.
Phlupp schrieb:> Steht da zufällig auch, warum man das für eine gute Idee gehalten hat?> Ignorieren hätte man es auch erst dann können, wenn es nicht mehr anders> geht.
Weil es keiner braucht, dafür gibt es (mittlerweile) constexpr.
Und da du dich ja beharrlich weigerst, constexpr zu verstehen:
1
#include<cstdint>
2
3
constexprintfactorial(constuint32_tn)
4
{
5
returnn<=1?1:(n*factorial(n-1));
6
}
7
8
intmain()
9
{
10
// computed by compiler
11
constuint32_tfact_4=factorial(4);
12
13
// volatile in argument forces calculation at runtime
The constexpr specifier declares that it is possible to evaluate the
value of the function or variable at compile time.
A constexpr specifier used in a function or static member variable
(since C++17) declaration implies inline.
Ich frage mich, wie manche Leute hier so eine einfache Frage dermaßen
aufblähen können - wohl zu viel heiße Luft..
Hier wissen einige wohl nicht, was Philosophieren bedeutet.
Bitte! lest euch nochmal gründlich den Eingangspost durch, wenn ihr euch
das zutraut..
Also der Reihe nach:
@Arduino Fanboy D.
>Nein!
..Doch..
>Da steht nicht was du erreichen möchtest, und vor allen Dingen nicht:>Warum?
Falsch: überladene Fkt + Unterscheidung Compilezeit-Konstante ("5") <->
Variable ("x").
"5" werden viele als sog. 'Zahl' erkennen und "x" als sog. 'Variable'
und 'überladen' als überladen.
Und du so?
Und wenn du nicht weißt, was alternativ, oder Algo bedeutet, sag
bescheid.
@ Rolf M.
>Und ich verstehe auch nicht, warum man die Berechnung bei zur>Compilezeit bekannten Werten weglassen können soll und was das 0x00>bedeuten soll.
0x00 -> 0b00000000, schon mal über 0en summiert?!
@ Peter D.
Dann doch lieber always inline ;). Zumindest gcc scheint das auch ohne
Hilfe hinzubekommen. Jedoch: Sicher ist sicher.
@M.K. B.
>Tut mit leid, ich bin raus.
Na, welch ein Zufall.. Warum nur habe ich das Gefühl, du warst nie
drin..
Du wirst uns doch nicht etwa deine meisterliche Lösung für das konkret
gestellte Problem vorenthalten? Oder gibt es sie etwa gar nicht?
>Offensichtlich hast du es nicht nötig, den>freiwilligen Helfern hier entgegen zu kommen.
Also wenn dir ein Danke nicht genügt, soll das dein Problem alleine
sein.
Helfern komme ich gerne entgegen, Hatern nicht.
@ Vincent H.
>Intuitiv wäre dass die const Version mit dem Literal aufgerufen wird.>Weil 5 aber nur vom Typ int ist würde das nie passieren... C++ ist zwar>klassisch die Sprache mit den falschen Defaults, aber das wäre absolut>irre.
Hmm, irgendwie kann ich deren Entscheidung noch immer nicht ganz
nachvollziehen. Du sagst ja selbst es wäre intuitiv, ein Literal als
const zu betrachten (btw. wer noch nie ein ..ul vergessen hat, werfe den
1. Stein). Sehe ich auch so.
Bei & wird das genau so gemacht, bei "Kopien" wird es bewusst ignoriert.
@ vn n.
>Tut mir leid, etwas Eigeninitiative kann man wohl doch erwarten.
Wie meinen? constexpr scheint mir nicht das, was ich bräuchte (wenn es
überhaupt ginge)!?
>Gar nix. Du verstehst nur die Sprache nicht, und solltest dir mal ein>gutes C++-Buch zulegen.>Weil es keiner braucht, dafür gibt es (mittlerweile) constexpr.
Na wer da wohl die Sprache nicht richtig verstanden hat.. Das
"mittlerweile" gehört absolut nicht in Klammern.. ;)
Dennoch Danke für dein ausführliches Beispiel. Trifft aber, wie schon
gesagt, nicht auf meinen Fall zu.
@ Peter D.
Das hilft nicht bei Überladung von pass-by-value-Funktionen und auch
nicht bei "halb-konstanten" Funktionen.
...aber das hatten wir alles schon...
Soweit mir bekannt, sind diejenigen, die andere für dumm halten wollen,
oft selbst nicht bereit ihr Hirn für etwas anderes als Kopfschmerzen zu
benutzen.
Theoretisch wäre das was der TO möchte schon umsetzbar. Der Compiler
trifft ja auch bei überladenen Funktionen mit und ohne constexpr die
richtige Entscheidung. Wenn man nun ein Argument der Funktion als
constexpr kennzeichnen würde, müsste das immer noch klappen. Praktisch
hatte wohl niemand Lust das zu implementieren. Daher gibt es nur
Funktionen, die entweder ganz constexpr sind oder gar nicht.
Mir fallen trotzdem 2 Lösungen ein.
1. Template Funktionen (so wäre wohl auch die Implementierung mit
constexpr Argumenten gelöst), mit ein bisschen TMP. Also sowas wie
foo(int x, int y) {if (is_literal(x)) templated_foo<x>(y) else ...}
Für die genaue Implementierung muss man da sicher noch hier und da ein
bisschen rumspielen. So fit bin ich nicht in TMP.
2. Die Funktion trennen und den optimierbaren Teil in eine constexpr
Funktion auslagern.
Phlupp schrieb:> "5" werden viele als sog. 'Zahl' erkennen und "x" als sog. 'Variable'> und 'überladen' als überladen.
Dass ein const Parameter nicht die Lösung sein kann, ist dir ja
hoffentlich mittlerweile klar.
Also funktioniert das auch mit dem Überladen nicht!
Immerhin bietet dir der Gcc die Chance, eine solche Konstante zu
erkennen.
Suche: __builtin_constant_p (exp)
Phlupp schrieb:> Wie meinen? constexpr scheint mir nicht das, was ich bräuchte (wenn es> überhaupt ginge)!?
Dann poste doch endlich mal ein ordentliches Codebeispiel, was du
erreichen willst, ich sehe nämlich nicht, constexpr nicht passt...