2015-11-18 7 views
10

Próbuję jakoś wyłączyć/oznaczyć jako przestarzałe ohydne przeciążenie std::string::operator=(char) (które w moim doświadczeniu jest używane tylko wtedy, gdy błędnie przypisuję liczbę całkowitą do napisu i powoduje subtelne i trudne śledzenie błędów).Jak oznaczyć * funkcję/metodę standardowej biblioteki * jako wycofaną (lub wyłączoną w ogóle) w moim projekcie?

Próbowałem z:

  • wyraźne specjalizacji ze statycznym dochodzić w nim

    #include <string> 
    #include <type_traits> 
    
    template<> std::basic_string<char> &std::basic_string<char>::operator=(char c) { 
        static_assert(false, "Don't use this!"); 
    } 
    

    która nie jak <string> już robi wyraźne konkretyzacji std::string

  • atrybutu [[deprecated]], zastosowane do podobnej deklaracji jak powyżej w różnych pozycjach; żadna pozycja, którą próbowałem, nie przyniosła żadnego rozsądnego rezultatu;
  • =delete, które zawiedzie z powodów podobnych do powyższych;
  • Pomyślałem o zastosowaniu sztuczek linkerów (w podobnym duchu, w tym samym projekcie mamy sprawdzanie w czasie wykonywania zabłąkanych setlocale zastosowań przy użyciu opcji linkera --wrapld), ale fakt, że jest to szablon i metoda inline, komplikuje sprawę.

teraz do pytania:

  • istnieje standardowa metoda jakoś wyłączyć (jak by się stało z =delete) dowolną funkcję lub metodę w bibliotece standardowej (czytaj: w bibliotece, gdzie nie można zmieniać deklaracje w nagłówkach)?
  • jak wyżej, ale zamiast wyłączać, dodaj ostrzeżenie (tak jak w przypadku [[deprecated]]);
  • w przypadku braku standardowej metody, czy jest coś g ++ - konkretnego?
  • jeśli nie ma rozwiązania "ogólnego" (= dotyczy dowolnej metody, dowolnej klasy, dowolnej funkcji, ...), czy jest coś, co moglibyśmy zastosować do tego konkretnego przypadku (= wyłączenie metody klasy szablonu, ewentualnie nawet konkretna instancja)?
+1

Masz śmieszne definicję „przestarzałe”, jeśli starasz się używać statycznego stwierdzenia lub usuniętą funkcję. –

+0

@ JonathanWakely: "przestarzałe lub całkowicie wyłączone"; ale o ile mi wiadomo, to w zasadzie takie same, to pewnie użyć '-Werror' na takiego ostrzeżenia w każdym razie, nie ma ważny powód, by użyć tego operatora przypisania (dokładnie tak, jak nie ma powodu, aby użyć, powiedzmy,' dostaje 'lub ciąg literal =>' char * 'oprócz zgodności ze starszym kodem). –

Odpowiedz

4

Można użyć następującego kompilatora/opcji linkera:

$ g++ -O0 test.cpp -Wl,--wrap=_ZNSsaSEc 

wyjaśnienie:

_ZNSsaSEc jest urządzony nazwa funkcji naruszającego:

$ echo _ZNSsaSEc | c++filt 
std::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator=(char) 

-Wl opcja kompilatora to przekazanie opcji do linkera.

Opcja łącznika --wrap=<symbol> przekształca dowolne odniesienie do danego symbolu na alternatywę __wrap_<symbol>. A skoro jesteś (mam nadzieję) nie definiujemy funkcję o nazwie __wrap__ZNSsaSEc, można uzyskać ładny błąd linkera:

test.cpp:(.text+0x26): undefined reference to `__wrap__ZNSsaSEc' 

i -O0 jest wyłączenie optymalizacji i zapobiec kompilatora z inline funkcję.Sztuczka linkera nie zadziała, jeśli zostanie wprowadzony, jak zauważył @SergeBallesta w komentarzu.

Może trochę hack, ale hej, to działa!

+1

@SergeBallesta: Cóż, z '-O0', to działa. Z '-O1' lub wyższym nie. – rodrigo

+0

Nie rób tego! Jest absolutnie nieoczywiste, że ten błąd wynika z niewłaściwie używanego operatora przypisania. Kilka lat później ta flaga linkera może być trudnym do śledzenia błędem. – Richard

1

Obawiam się, że standardowa biblioteka ma być ... standard, a jako taka nie zapewnia haków, aby umożliwić programistom ich modyfikację.

Jest brzydki sposób (nie mów nigdy Radzę zrobić używać go ;-)) byłoby wykorzystanie faktu, że nagłówki Biblioteka standardowa są tylko plików tekstowych, dzięki czemu można łatwo zmienić je w lokalnym środowisku DÉVELOPPEMENT Ciebie. Prawdopodobnie mniej zły sposób polega na skonfigurowaniu folderu zawierającego łącza do oryginalnych nagłówków z wyjątkiem zmodyfikowanego nagłówka i poinstruowania kompilatora, aby używał tego folderu do nagłówków systemu.

W ten sposób można zmieniać wszystko, co chcesz, ale ... przenośność i konserwacji ... To naprawdę desperado rozwiązanie ...

+0

Pierwsze zdanie jest trochę kwestią sporną; weź dowolny dynamiczny język do wyboru (JavaScript, Python, Ruby, ...), tam * jest * standardową biblioteką, ale można ją przekręcić w najbardziej dziwaczny sposób; również biblioteka standardowa C++ zapewnia punkty dostosowywania (jako argumenty szablonu lub jako "otwarte funkcje", think 'std :: hash'), POSIX i Win32 umożliwiają warunkowe dołączanie rzeczy za pomocą makr, a wszystkie konkretne implementacje C++ pozwalają na flagę lub dostosowania do standardowej biblioteki, a nawet do samego języka (jako przełączniki kompilacji dla kompilatora, jako makra do zdefiniowania, ...). –

0

To dzyń ++ specyficzny, ponieważ nie wiem co odpowiednia funkcjonalność jest wywoływana w toolchainie gnu. Jest to również trochę przesada.

sugestia Rodrigo korzystania z łącznika, aby zamienić się symbol jest dobre dla non-inlined przypadkach. Jeśli budujesz wszystko w O0 okazjonalnie, to wystarczy.

przeciwnym razie llvm (szczęk) toolchain oferuje zaskakujące ilości kontroli nad rurociągiem optymalizacji. Można na przykład kompilować bez optymalizacji, a następnie uruchamiać optymalizacje za pomocą opcji opt, a następnie konwertować do pliku obiektowego.

clang++ -c test.cpp -O0 --emit-llvm test.ll 
opt -O3 test.bc -o faster.ll 
clang++ -c faster.bc -o test.o 

Narzędzie opt jest rozszerzalne. Nie mogę szczerze powiedzieć, że rozszerzenie jest banalne, ale proces jest dobrze udokumentowany. Możesz napisać przepustkę kompilatora ostrzegającą, gdy zobaczysz swoją standardową funkcję biblioteki. Końcowym rezultatem może być wywołana coś takiego:

clang++ -c test.cpp -O0 --emit-llvm test.ll 
opt --load DeprecationPass.so test.bc -o /dev/null 
opt -O3 test.bc -o faster.ll 
clang++ -c faster.bc -o test.o 

Jeśli jesteś pewny, że zwyczaj pass jest prawidłowe (nie tylko użyteczny), można użyć jednego wywołanie opt. Prawdopodobnie można przekazać flagi, aby zdecydować się na front, ale nie jest to od razu oczywiste.

Ogólnie rzecz biorąc, po sugestii Rodrigo i od czasu do czasu budowy całego produktu w O0 jest prawdopodobnie lepszy plan - ale to jest ekscytujące, że dzyń pozwala robić takie rzeczy.

Powiązane problemy