Seite 1 von 1

call to namespace function

Verfasst: 09.11.2011, 23:47
von BeRsErKeR
Folgendes Beispiel:

Code: Alles auswählen

namespace foo
{
void bar(){}
}

int main(int argc, char **argv)
{
bar();
return 0;
}
Ist es normal, dass bar gefunden wird, obwohl ich weder ein using namespace benutze, noch einen namespace voranstelle? Mit dem g++ 4.4.3 funktioniert das jedenfalls und der gdb springt auch wirklich in foo::bar.

Meine Frage ist nun, steht das im Standard drin, dass das möglich ist? Also wenn es nur eine passende Funktion gibt, dass er auch die namespaces durchsucht und diese nutzt? Fände ich ziemlich kacke.

Oder hab ich da vielleicht nen namespace nicht geschlossen? Wobei ich dann eigentlich Compilerfehler erwarten würde. Komischerweise geht eine weitere Funktion nicht, die direkt unter bar deklariert wird. Die findet er nicht ... die hat allerdings auch ein template.

Re: call to namespace function

Verfasst: 09.11.2011, 23:49
von Aramis
Er darf bar nicht finden. Ausser dein Beispiel ist vereinfacht und ADL greift.

Re: call to namespace function

Verfasst: 10.11.2011, 00:27
von dot
Jop. Wenn dein echtes bar einen Parameter eines Typs, der in foo liegt bekommt, dann greift ADL und die Welt ist in Ordnung. Das Beispiel so darf jedenfalls nicht kompilieren. Aber wer weiß was gcc da schon wieder treibt ;)

Re: call to namespace function

Verfasst: 10.11.2011, 00:34
von BeRsErKeR
ADL?

Naja bar ist eine friend-Methode eines Types, der in foo liegt. Allerdings kennt er diesen Typ auch nicht, wenn ich den namespace nicht dranschreibe.

Re: call to namespace function

Verfasst: 10.11.2011, 00:38
von dot

Re: call to namespace function

Verfasst: 10.11.2011, 00:40
von BeRsErKeR
Danke für die Info. Ok die Funktion bekommt auch einen Parameter der was aus dem namespace enthält. Also wohl ADL. Find ich ehrlich gesagt aber doof. Sollte wenigstens eine Warnung kommen bzw. er sollte das gar nicht machen.

Re: call to namespace function

Verfasst: 10.11.2011, 00:42
von dot
Wenn er das nicht machen würde, dann würd schon das übliche Hello World nichtmehr kompilieren ;)

Ich find ADL ist ein wirklich praktisches Feature von C++.

Re: call to namespace function

Verfasst: 10.11.2011, 01:30
von BeRsErKeR
Wieso sollte er das nicht kompilieren, wenn überall ein std:: vor steht, so wie es sich gehört?

Re: call to namespace function

Verfasst: 10.11.2011, 01:36
von dot
Dann müsste es so aussehen:

Code: Alles auswählen

#include <iostream>

int main()
{
  std::operator <<(std::operator <<(std::cout, "hello, world"), std::endl);
}
Find ich jetzt nicht so berauschend...

Re: call to namespace function

Verfasst: 10.11.2011, 16:41
von Aramis
Kurz formuliert: er findet den operator << im Hello-World ohne using namespace std; nur weil einer der beiden Operanden (z.b. cout) selber in std lebt.

Re: call to namespace function

Verfasst: 10.11.2011, 18:01
von BeRsErKeR
Ok. Das gilt allerdings nur für strings. Wo wir gerade dabei sind, wieso sind eigentlich die <<-Operatoren für strings global und nicht Teil der stream-Klasse? Das frag ich mich schon eine ganze Weile, zumal die sich auch prima als Klassenmethode implementieren lassen.

Re: call to namespace function

Verfasst: 10.11.2011, 19:29
von Krishty
Weil das Schreiben von Strings in Output-Streams weder ein Implementierungsdetail der String-Klasse ist, noch eins der Output-Stream-Klasse.

Es gibt auch irgendwo einen tollen Artikel, der zeigt, dass std::string mit seinen 80 Methoden ekelhaft überladen ist und man mehr als die Hälfte davon besser außerhalb der Klasse hätte realisieren sollen.

Re: call to namespace function

Verfasst: 10.11.2011, 19:50
von BeRsErKeR
Krishty hat geschrieben:Weil das Schreiben von Strings in Output-Streams weder ein Implementierungsdetail der String-Klasse ist, noch eins der Output-Stream-Klasse.
Und wieso ist das Schreiben von int, float und Co ein Implementierungsdetail der Output-Stream-Klasse?

Re: call to namespace function

Verfasst: 10.11.2011, 19:57
von kaiserludi
Krishty hat geschrieben:Weil das Schreiben von Strings in Output-Streams weder ein Implementierungsdetail der String-Klasse ist, noch eins der Output-Stream-Klasse.
und weil der Operator nicht zwingend Zugriff auf irgendwelche private oder protected Variablen/Methoden einer der beiden Kalssen braucht, sondern wunderbar mit reinem Zugriff auf die public Interfaces der Klassen auskommt und natürlich, weil dank namespaces globale Funktionen nicht mehr das Risiko von Namenskollisionen erhöhen, sofern der Benutzer von der Unart absieht, alles und jeden mit "using namespace" einzubinden.

Habe irgendwo mal den interessanten Satz gelesen:
"Java- und C#-Programmierer werden verwundert sein, aber in C++ ist die objekorientierteste Art der Implementation einer Funktionlität keine Klassenmethode, sondern eine globale Funktion im gleichen Namespace wie die Klass, da sie so nciht mehr Zugriffsrechte bekomtm, als sie auch braucht."
Alles, was an privates rumpfuschen kann, ohne das tatsächlich zu müssen, erhöht nur das Risiko, dass der Wartungsaufwand sich erhöht, weil alles innerhalb der Klasse kreuz und quer auf Sachen zugreift, auf die es gar nicht zugreifen bräuchte. Alles, was nur übers öffentliche Itnerface drauf zugreift, muss nicht angefasst werden, sofern man nur an Implementierungsdetails was dreht und wenn man es doch umbauen muss, dann weiß man auch sofort, dass man anscheinend versehentlich doch das Interface verändert hat (z.B. durch Seitenwirkungen (um in der Diskussion Seiteneffekte/Nebeneffekte/Nebenwirkungen keinen zu bevorzugen ;) ) ).

Hat aber auch Vorteile, alles als Membermethoden von Klassen zu implementieren: So ist das ganze Interface eienr Klasse auch im Header in dieser zu finden und liegt nicht sonst wo verstreut in deinem potentiell rieisigen Namespace rum. Gerade wenn eine Methode oder ein Operator aber genauso gut zu einer anderen Kalsse gehören könnte, man es verstärkt Sinn, darüber nach zu denken, ihn/sie als gloable(n) Operator/Funktion in dem Namespace einzubauen.

Das erklärt dann auch, wieso es bei primitiven Datentypen wie intoder float anders gelöst ist:
Hier stellt sich die Frage nicht, in welcher von beiden Kalssen man es implementiert, in dem primitiven Typ geht nun mal schlecht, ohne, dass man eine Wrapperklasse drumherum aufbaut, die dann aus Performancegründen nicht überall genutzt wird.
Inkonsistent ist das trotzdem irgendwie.

Re: call to namespace function

Verfasst: 10.11.2011, 20:19
von Krishty
Amen.

Re: call to namespace function

Verfasst: 12.11.2011, 22:33
von BeRsErKeR
Ich frage mich nur warum der Operator für bestimmte Typen (wohlgemerkt Standardtypen) als Member und für andere global implementiert ist. Das macht für mich keinen Sinn.

Re: call to namespace function

Verfasst: 12.11.2011, 22:36
von Krishty
Auf welche beziehst du dich im Speziellen?

Re: call to namespace function

Verfasst: 13.11.2011, 01:57
von BeRsErKeR
Member:

Code: Alles auswählen

ostream& operator<< (bool val);
ostream& operator<< (short val);
ostream& operator<< (unsigned short val);
ostream& operator<< (int val);
ostream& operator<< (unsigned int val);
ostream& operator<< (long val);
ostream& operator<< (unsigned long val);
ostream& operator<< (float val);
ostream& operator<< (double val);
ostream& operator<< (long double val);
ostream& operator<< (const void* val);
Globale Funktionen:

Code: Alles auswählen

ostream& operator<< (ostream& out, char c );
ostream& operator<< (ostream& out, signed char c );
ostream& operator<< (ostream& out, unsigned char c );
 
ostream& operator<< (ostream& out, const char* s );
ostream& operator<< (ostream& out, const signed char* s );
ostream& operator<< (ostream& out, const unsigned char* s );

Ich denke allerdings ich weiß nun warum dem so ist. Jedenfalls vermute ich das. Und zwar können obige Typen in verschiedenen Formen durch IO Manipulatoren angezeigt werden und das werden dann sicherlich interne streamabhängige Flags (z.B. hex, oct, precision) sein, daher können die <<-Operatoren nicht global sein. Korrigiert mich wenn ich mich irre, klingt allerdings plausibel.

Re: call to namespace function

Verfasst: 13.11.2011, 09:29
von Krishty
Ja, das klingt in der Tat plausibel.

Ich bin auch ein wenig verblüfft, dass char und char const * global sind – ich persönlich hätte vor allem die beiden zu Methoden gemacht und alles andere darauf aufgebaut.

Re: call to namespace function

Verfasst: 13.11.2011, 14:39
von BeRsErKeR
Genau das hatte mich ja verwundert. Allerdings macht es in Hinblick auf die IO Manipulatoren und die ostream Methoden put und write schon Sinn.