2016-04-10 11 views

Odpowiedz

28

Czy w C++ 11 i nowszych można specjalizować std :: to_string w przestrzeni nazw standardowej dla typów niestandardowych?

Nie. Po pierwsze, it is not a template function, więc nie można w ogóle go wyspecjalizować.

Jeśli pytasz o dodanie własnych funkcji przeciążania, odpowiedź pozostaje taka sama.

Dokumentacja urywek z Extending the namespace std:

pozostaje niezdefiniowana zachowanie dodawania deklaracji lub definicji do namespace std lub do dowolnej przestrzeni nazw zagnieżdżony w std, z kilkoma wyjątkami odnotowanych poniżej

Dozwolone jest dodanie specjalizacja szablonów dla dowolnego standardowego szablonu biblioteki do przestrzeni nazw standardowej tylko wtedy, gdy deklaracja zależy od typu zdefiniowanego przez użytkownika, a specjalizacja spełnia wszystkie wymagania dotyczące oryginalnego szablonu, z wyjątkiem przypadków, gdy takie specjalizacje są zabronione.


W praktyce wszystko będzie prawdopodobnie działać dobrze, ale ściśle mówiąc standard mówi, że nie ma żadnej gwarancji, co się wydarzy.


Edit: Nie mam dostępu do oficjalnego standardu więc po to z free working draft (N4296):

17.6.4.2 wykorzystania przestrzeni nazw

17.6.4.2.1 Przestrzeń nazw std

  1. Zachowanie Program w C++ jest niezdefiniowany, jeśli dodaje deklaracje lub definicje do przestrzeni nazw standardowej lub do przestrzeni nazw w przestrzeni nazw standardowej, chyba że określono inaczej. Program może dodać szablon specjalizacji dla dowolnego standardowego szablonu biblioteki do przestrzeni nazw standardowej tylko wtedy, gdy deklaracja zależy od zdefiniowanego przez użytkownika typu , a specjalizacja spełnia standardowe wymagania biblioteki dla oryginalnego szablonu i nie jest jawnie zabroniona .
  2. Zachowanie się program w C++ jest niezdefiniowana jeśli deklaruje

    2.1 - wyraźna specjalizacja jakiejkolwiek funkcji składowej standardowego szablonu Class Library lub

    2.2 - wyraźna specjalizacja dowolny elementowy szablon funkcji standardowej biblioteki lub szablonu klasy, lub

    2.3 - wyraźna lub częściowa specjalizacja dowolnego szablonu klasy członków standardowej klasy biblioteki lub szablonu klasy .

    Program może jawnie utworzyć szablon zdefiniowany w bibliotece standardowej tylko wtedy, gdy deklaracja zależy od nazwy typu zdefiniowanego przez użytkownika, a instancja spełnia standardowe wymagania biblioteki dla oryginalnego szablonu.

  3. Jednostka tłumaczeniowa nie deklaruje przestrzeni nazw jako standardowej przestrzeni nazw (7.3.1).
+2

Brak gwarancji .. Nieokreślony? Nie mogę uwierzyć, że to nieokreślone zachowanie. Specjalizacja dla każdej innej przestrzeni nazw działa dobrze. Wątpię, by wystąpiły jakiekolwiek konsekwencje w zakresie zachowań programowych. Myślę, że standard powinien po prostu powiedzieć, że jest zabroniony i nie nazwać go niezdefiniowanym, jeśli tak naprawdę nie jest. W jaki sposób może to spowodować niezdefiniowane zachowanie? – Brandon

+10

@Bandon: Generalnie oczekujemy, że kompilatory będą pomyłki, gdy robimy zabronione rzeczy, ale wymaganie od kompilatorów wykrywania i diagnozowania tego typu rzeczy jest nierealne. Stąd UB. –

+0

To jest smutne. Szkoda, że ​​nie zrobią wyjątku dla 'std :: to_string'. Lub jako alternatywa, zapewnij inne sposoby specjalizacji, np. przy użyciu czegoś takiego jak 'template auto f (T && t) -> std :: enable_if_t > :: value, void> {ToStringSpec >() (std :: forward (t)); } ' – jotik

9

Jeśli się nie mylę można po prostu przeciążać to_string dla typu rodzajowego:

template<typename T> to_string(const T& _x) { 
    return _x.toString(); 
} 

a to pozwala na korzystanie z ADL (argumentem wyszukiwanie zależne) przez twój program, aby poprawnie wybrać odpowiednią metodę to_string w oparciu o przekazany typ.

+1

sugerujesz to zrobić w przestrzeni nazw 'std' lub poza nią? –

+5

@JamesAdkison Poza tym – ArchbishopOfBanterbury

+1

Działa to tylko dla niewykwalifikowanych wywołań funkcji, takich jak 'to_string (myObject)', ale nie dla kwalifikowanych wywołań funkcji, takich jak 'std :: to_string (myObject)'. – jotik

7

Lepszy sposób byłoby utworzyć własną funkcję korzystania z std::to_string jeśli jest to możliwe, jak również .toString() metody, gdy jest ona dostępna dla przeszedł argumentu:

#include <type_traits> 
#include <iostream> 
#include <string> 

struct MyClass { 
    std::string toString() const { return "MyClass"; } 
}; 

template<class T> 
typename std::enable_if<std::is_same<decltype(std::declval<const T&>().toString()), std::string>::value, std::string>::type my_to_string(const T &t) { 
    return t.toString(); 
} 

template<class T> 
typename std::enable_if<std::is_same<decltype(std::to_string(std::declval<T&>())), std::string>::value, std::string>::type my_to_string(const T &t) { 
    return std::to_string(t); 
} 

int main() { 
    std::cout << my_to_string(MyClass()) << std::endl; // will invoke .toString 
    std::cout << my_to_string(1) << std::endl; //will invoke std::to_string 
} 
Powiązane problemy