为什么编译器选择 bool 而不是 string 来隐式类型转换 L""?

2021-12-22 00:00:00 visual-c++ implicit c++ explicit

最近引入了一个方法的重载,应用程序开始失败.终于追查到了,新方法在我没想到的地方被调用了.

Having recently introduced an overload of a method the application started to fail. Finally tracking it down, the new method is being called where I did not expect it to be.

我们有

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 值时我们使用相同的字符串(字符串的内部数据存储)

It was changed so that when a bool value is stored we use the same strings (internal data storage of strings)

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

The problem with L"" is that it is implicitly casting and previously it was happy to be a std::wstring, but not it prefers to be a bool. The MSVC compiler does not complain, or raise warning, so I'm worried that even if I "fix" the setValue( L"empty", L"" ); to be

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

其他人可能会稍后来,只需使用 setValue( L"empty", L"" );并且必须再次追踪此问题.

somebody else may come later and simply use setValue( L"empty", L"" ); and have to track down this issue again.

我们想在方法上使用显式,但它不是此用法的有效关键字.有没有办法让编译器抱怨这个,或者以其他方式防止这个问题?否则,我正在考虑更改采用 bool 的方法的名称,以确保它不会做出错误的猜测.

We thought to use explicit on the method but it is not a valid keyword for this usage. Is there some way to get the compiler to complain about this, or otherwise prevent the issue? Otherwise I'm thinking to change the name of the method which takes a bool to ensure it can't make an incorrect guess.

推荐答案

一、此问题的原因:C++标准[over.ics.rank]/2.11 定义了转换序列的顺序.它说用户定义的转换序列比标准转换序列更糟糕.在您的情况下,字符串文字会进行布尔转换(在 4.12 中定义.这是标准转换).它不使用用户定义的到 std::wstring 的转换,如果它采用其他重载,则需要这种转换.

First, the cause of this issue: C++ Standard [over.ics.rank]/2.11 defines an order for conversion sequences. It says that a user defined conversion sequence is worse than a standard conversion sequence. What happens in your case is that the string literal undergoes a boolean-conversion (defined at 4.12. This is a standard conversion). It does not use the user defined conversion to std::wstring which would be needed if it took the other overload.

我建议简单地更改重载之一的名称或添加直接接受字符串文字的重载(使用参数类型 wchar_t const*).

I would recommend to simply change the name of one of the overloads or adding an overload that accepts the string literal directly (using parameter type wchar_t const*).

1)

比较隐式转换序列的基本形式时(如[over.best.ics]中所定义)

When comparing the basic forms of implicit conversion sequences (as defined in [over.best.ics])

(2.1) 标准转换序列是比用户定义的转换序列或省略号转换序列更好的转换序列,并且
(2.2) 自定义转换序列比省略号转换序列更好.

(2.1) a standard conversion sequence is a better conversion sequence than a user-defined conversion sequence or an ellipsis conversion sequence, and
(2.2) a user-defined conversion sequence is a better conversion sequence than an ellipsis conversion sequence.

相关文章