Почему компилятор выбирает bool вместо string для неявного преобразования типов в L ""? - PullRequest
11 голосов
/ 25 ноября 2008

Недавно введя перегрузку метода, приложение начало сбой. Наконец, отслеживая его, новый метод вызывается там, где я не ожидал.

У нас было

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"" );

Он был изменен таким образом, чтобы при сохранении значения bool мы использовали одни и те же строки (внутреннее хранилище данных строк)

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!?!

Проблема с L "" заключается в том, что он неявно приводится, и ранее он был счастлив быть std :: wstring, но не предпочитал быть bool. Компилятор MSVC не жалуется и не выдает предупреждение, поэтому я беспокоюсь, что даже если я "исправлю" setValue (L "empty", L ""); быть

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

кто-то другой может прийти позже и просто использовать setValue (L "empty", L ""); и придется снова выследить эту проблему.

Мы подумали использовать явный метод, но это недопустимое ключевое слово для этого использования. Есть ли какой-нибудь способ заставить компилятор жаловаться на это или иным образом предотвратить проблему? В противном случае я думаю поменять имя метода, который использует bool, чтобы убедиться, что он не может сделать неправильное предположение.

Ответы [ 5 ]

12 голосов
/ 25 ноября 2008

Во-первых, причина этой проблемы: C ++ Standard [over.ics.rank]/2.1 1 определяет порядок для последовательностей преобразования. Это говорит о том, что определенная пользователем последовательность преобразования хуже, чем стандартная последовательность преобразования. Что происходит в вашем случае, так это то, что строковый литерал подвергается булевому преобразованию (определено в 4.12. Это стандартное преобразование). Он не использует пользовательское преобразование в std::wstring, которое понадобилось бы, если бы потребовалась другая перегрузка.

Я бы порекомендовал просто изменить имя одной из перегрузок или добавить перегрузку, которая принимает строковый литерал напрямую (используя тип параметра wchar_t const*).


1)

При сравнении основных форм последовательностей неявного преобразования (как определено в [over.best.ics])

(2.1) стандартная последовательность преобразования является лучшей последовательностью преобразования, чем определяемая пользователем последовательность преобразования или многоточия преобразования, и
(2.2) определяемая пользователем последовательность преобразования является лучшей последовательностью преобразования, чем последовательность преобразования многоточия.

8 голосов
/ 25 ноября 2008

L "" - указатель на строку широких символов. Компилятор считает, что преобразование в bool имеет приоритет перед преобразованием в std :: wstring.

Чтобы устранить проблему, введите новое значение set:

void setValue(std::wstring const& name, const wchar_t * value);
2 голосов
/ 25 ноября 2008

Поскольку bool является встроенным типом, преобразование из wchar_t в bool является предпочтительным. Я бы сказал, что самое простое решение состоит в том, чтобы добавить перегрузку, которая принимает массив wchar_t и явно приводит туда:

setValue( const std::wstring& name, const wchar_t s[] )
{
     setValue(name, wstring(s));
}
1 голос
/ 25 ноября 2008

Чтобы упростить немного, следующий код

#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");  }

печатает " bool version называется". Вы уверены, что ваш код дает сбой только с пустой строкой?

0 голосов
/ 25 ноября 2008

Вы можете сделать так, чтобы новая функция принимала какой-то другой тип, кроме bool - возможно, просто прокси для bool - который не может быть преобразован из буквальной строки. Но на самом деле я бы просто переименовал функцию получения булла и покончил с этим.

...