Dlaczego moje logowanie jest w przestrzeni nazw std?

W poniższym kodzie definiuję trywialną funkcję log. W main staram się , a nie nazywać go; wzywam std::log. Niemniej jednak, mój własny log jest nazywany; i widzę " log!"na ekranie. Czy ktoś wie dlaczego? Używam G++ 4.7 i clang++ 3.2.

#include <iostream>
#include <cmath>

double log(const double x) { std::cout << "log!\n"; return x; }

int main(int argc, char *argv[])
{
  std::log(3.14);
  return 0;
}
Author: user2023370, 2012-08-10

5 answers

C++ Standard 17.6.1.2 paragraf 4 (podkreślenie):

Z wyjątkiem przypadków wymienionych w pkt 18-30 i załączniku D, zawartość każdego nagłówka cname jest taka sama jak zawartość odpowiedniego nagłówka name.h, Jak określono w bibliotece standardowej C (1.2) lub w C Unicode TR, stosownie do przypadku, tak jakby przez włączenie. W bibliotece standardowej C++ deklaracje (z wyjątkiem nazw, które są zdefiniowane jako makra w C) znajdują się w obszarze przestrzeni nazw (3.3.6) przestrzeni nazw std. nie jest określone, czy te nazwy są najpierw zadeklarowane w globalnym zakresie przestrzeni nazw, a następnie są wstrzykiwane do przestrzeni nazw {[2] } przez jawne za pomocą-declarations (7.3.3).

G++ robi to w ten drugi sposób, aby niektóre z tych samych plików nagłówkowych mogły być ponownie użyte w C i C++. Tak więc g++ może deklarować i definiować double log(double) w globalnej przestrzeni nazw.

Sekcja 17.6.4.3.3 ustępy 3 i 4:

Każda nazwa ze standardowej biblioteki C zadeklarowana z linkiem zewnętrznym jest zarezerwowana dla implementacji do użycia jako nazwa z linkiem extern "C", zarówno w przestrzeni nazw std, jak i w globalnej przestrzeni nazw.

Każda sygnatura funkcji ze standardowej biblioteki C zadeklarowanej z zewnętrznymi powiązaniami jest zarezerwowana dla implementacji do użycia jako sygnatura funkcji z powiązaniami extern "C" i extern "C++", lub jako nazwa zakresu przestrzeni nazw w globalnej przestrzeni nazw.

I na górze sekcji 17.6.4.3 pkt 2:

Jeśli program deklaruje lub definiuje nazwę w kontekście, w którym jest zarezerwowana, innym niż wyraźnie dozwolony przez tę klauzulę, jego zachowanie jest niezdefiniowane.

Ty natomiast możesz Nie deklarować ani definiować ::log w jakikolwiek sposób.

Szkoda, że łańcuch narzędzi g++ nie daje żadnych komunikatów o błędach.

 55
Author: aschepler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-09 23:02:46

Spodziewam się, że std::log po prostu deleguje się do ::log. Niestety, ::log zapewnia tylko float przeciążenie, a Ty uprzejmie zapewniasz double przeciążenie, dzięki czemu Twoje lepiej pasuje. Ale nadal nie widzę, jak to się w ogóle bierze pod uwagę w zestawie przeciążeniowym.

 8
Author: Puppy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-09 22:46:28

W libstdc++'s cmath zobaczysz to:

using ::log;
/ Align = "left" / funkcje h z globalnej przestrzeni nazw do std. Niestety dostarczasz implementację dla double log(double), więc linker nie będzie używał tej z biblioteki matematycznej. więc zdecydowanie błąd w libstdc++.

EDIT: twierdzę, że jest to błąd w libstdc++, ponieważ std::log nie powinien cierpieć z powodu ingerencji w bibliotekę C, gdy wyraźnie prosisz o wersje std::. Oczywiście, tędy. aby nadpisać funkcje biblioteki standardowej jest stara "funkcja"z języka C.

EDIT 2: dowiedziałem się, że standard nie zabrania wprowadzania nazw z globalnej przestrzeni nazw do std. Nie jest to więc jednak błąd, a jedynie konsekwencja szczegółów implementacji.

 8
Author: DanielKO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-09 22:58:18

W C++ kompilator może dowolnie implementować bibliotekę C w globalnej przestrzeni nazw i delegować do niej (jest to implementacja zdefiniowana).

17.6.1.2.4 z wyjątkiem przypadków wymienionych w pkt 18-30 i załączniku D, zawartość każdego nagłówka cname jest taka sama jak nazwa odpowiedniego nagłówka.h, jak określono w bibliotece standardowej C (1.2) lub w Unicode C TR, w stosownych przypadkach, tak jakby przez włączenie. W bibliotece standardowej C++, jednak deklaracje (z wyjątkiem nazwy zdefiniowane jako makra w języku C) znajdują się w obszarze przestrzeni nazw (3.3.6) std. jest nie jest określone, czy te nazwy są najpierw deklarowane w globalnym zakresie przestrzeni nazw, a następnie wstrzykiwane do przestrzeni nazw std poprzez jawne użycie-deklaracje (7.3.3).

Ogólnie rzecz biorąc, unikałbym tworzenia funkcji z tym samym podpisem, co jedna z bibliotek standardu C. standard C++ z pewnością daje kompilatorom swobodę używania tych podpisów, jeśli tak wybierze, co oznacza, że możesz walczyć ze swoim kompilatorem, jeśli spróbujesz użyć tych samych podpisów. Stąd masz dziwne wyniki.

Spodziewałbym się jednak błędu linkera lub ostrzeżenia i myślę, że warto to zgłosić.

[edytuj]

Wow, ninja ' D.

 6
Author: Cornstalks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-09 23:06:29

Ponieważ nadpisałeś go w globalnej przestrzeni nazw. Użycie przestrzeni nazw pozwala uniknąć tego niebezpieczeństwa, jeśli nie chcesz przejść do bezpieczniejszego, czystszego języka, takiego jak na przykład Nim .

Właściwe użycie przestrzeni nazw demo :

#include <iostream>
#include <cmath>  // Uses ::log, which would be the log() here if it were not in a namespace, see http://stackoverflow.com/questions/11892976/why-is-my-log-in-the-std-namespace

// Silently overrides std::log
//double log(double d) { return 420; }

namespace uniquename {
    using namespace std;  // So we don't have to waste space on std:: when not needed.

    double log(double d) {
        return 42;
    }

    int main() {
        cout << "Our log: " << log(4.2) << endl;
        cout << "Standard log: " << std::log(4.2);
        return 0;
    }
}

// Global wrapper for our contained code.
int main() {
    return uniquename::main();
}

Wyjście:

Our log: 42
Standard log: 1.43508
 0
Author: Cees Timmerman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-06 01:51:41