2008-11-25 15 views
11

Po niedawnym wprowadzeniu przeciążenia metody aplikacja zaczęła zawieść. W końcu go śledząc, nowa metoda jest wywoływana tam, gdzie nie oczekiwałam.Dlaczego kompilator wybiera bool over string dla niejawnej typecast L ""?

Mieliśmy

setValue(const std::wstring& name, const std::wstring& value); 

std::wstring avalue(func()); 
setValue(L"string", avalue); 
std::wstring bvalue(func2() ? L"true", L"false"); 
setValue(L"bool", bvalue); 
setValue(L"empty", L""); 

został zmieniony tak, że gdy wartość bool jest przechowywany używamy tych samych ciągów (przechowywania danych wewnętrznych ciągów)

setValue(const std::wstring& name, const std::wstring& value); 
setValue(const std::wstring& name, const bool& value); 

std::wstring avalue(func()); 
setValue(L"string", avalue); 
setValue(L"bool", func2()); 
setValue(L"empty", L""); << --- this FAILS!?! 

Problem z L „” jest że jest to domyślnie rzucanie, a wcześniej było szczęśliwe bycie std :: wstringiem, ale nie woli być boolem. Kompilator MSVC nie narzeka, ani nie ostrzega, więc obawiam się, że nawet jeśli "naprawię" wartość setValue (L "empty", L ""); być

setValue(L"empty", std::wstring()); 

ktoś inny może przyjść później i po prostu użyć setValue (L "pusty", L ""); i ponownie musimy wyśledzić ten problem.

Pomyśleliśmy użyć jawnie w tej metodzie, ale nie jest to poprawne słowo kluczowe dla tego użycia. Czy istnieje sposób, aby kompilator mógł złożyć skargę na ten temat lub w inny sposób zapobiec problemowi? W przeciwnym razie zastanawiam się, czy zmienić nazwę metody, która ma wartość bool, aby upewnić się, że nie może ona złożyć błędnego wyniku.

+0

Dodałem do mojej listy powodów, dla których C++ nie jest najlepszym językiem. – Qix

Odpowiedz

10

Po pierwsze, przyczyną tego problemu: Standard C++ 13.3.3.2 definiuje kolejność sekwencji konwersji. Mówi, że zdefiniowana przez użytkownika sekwencja konwersji jest gorsza niż standardowa sekwencja konwersji. Co się dzieje w twoim przypadku, to że literał ciągu ulega konwersji boolowskiej (zdefiniowanej na 4.12. Jest to standardowa konwersja). Nie używa on zdefiniowanej przez użytkownika konwersji na std::wstring, która byłaby potrzebna, gdyby zajęła inne przeciążenie.

Polecam po prostu zmienić nazwę jednego z przeciążeń lub dodać przeciążenie, które akceptuje literał ciągu bezpośrednio (przy użyciu parametru typu wchar_t const*).

+0

Dzięki za link do standardu i wrappera dla bool również była pomocna wskazówka. –

+0

Zacytowałem wtedy niewłaściwy standardowy tekst i uznałem, że moja odpowiedź jest bez kompleksów. Dodanie oveload dla 'wchar_t const *' jest lepsze, jak sądzę. Możesz teraz dać znacznik wyboru Mark-Ransom, który zasadniczo mówi to samo. –

0

Moglibyśmy sprawić, by nowa funkcja działała inaczej niż bool - może po prostu proxy dla bool - którego nie można przekształcić z literalnego ciągu znaków. Ale tak naprawdę po prostu zmieniam nazwę funkcji bool-up i skończę z tym.

1

Aby uprościć nieco, następujący kod

#include <iostream> 
using namespace std; 

void f(const string &s) 
{ cout << "string version called" << endl; } 

void f(const bool &b) 
{ cout << "bool version called" << endl; } 

int main() 
{ f("Hello World"); } 

drukuje "bool wersja zwana". Czy jesteś pewien, że twój kod zawodzi tylko z pustym łańcuchem?

+0

Obecnie nie używamy literału łańcuchowego z wyjątkiem pustego łańcucha. Uważam, że masz rację, że nie ma to nic wspólnego z pustym ciągiem. –

+0

Literał ciągu nie musi być pusty, kompilator zawsze preferuje rzutowanie do bool'a do initalizacji klasy ciągów. Nawiasem mówiąc, myślę, że widziałem ostrzeżenia w VC++ 2005 dotyczące "forsowania wartości do bool". – MP24

8

L "" jest wskaźnikiem do szerokiego łańcucha znaków. Kompilator uważa, że ​​konwersja na wartość bool ma pierwszeństwo przed konwersją na std :: wstring.

Aby rozwiązać ten problem, należy wprowadzić nową setValue:

void setValue(std::wstring const& name, const wchar_t * value); 
+2

Niezupełnie. L "" jest literałem o szerokim łańcuchu znaków. – ChrisN

2

Ponieważ jest wbudowany w typie, preferowany jest konwersja z wchar_t do bool bool. Powiedziałbym, że najprostszym rozwiązaniem jest dodanie przeciążenia, które pobiera tablicę wchar_t i rzutuje się tam: