【问题标题】:Why does the compiler choose bool over string for implicit typecast of L""?为什么编译器为 L"" 的隐式类型转换选择 bool 而不是字符串?
【发布时间】:2008-11-25 02:32:08
【问题描述】:

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

我们有

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

改变了,当存储一个布尔值时,我们使用相同的字符串(字符串的内部数据存储)

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 的方法的名称,以确保它不会做出错误的猜测。

【问题讨论】:

  • 添加到我的 C++ 不是最佳语言的原因列表中。

标签: c++ visual-c++ implicit explicit


【解决方案1】:

首先,这个问题的原因:C++ 标准[over.ics.rank]/2.11 定义了转换序列的顺序。它表示用户定义的转换序列比标准转换序列差。在您的情况下发生的是字符串文字经历了布尔转换(在4.12 定义。这是标准转换)。它不使用用户定义的到std::wstring 的转换,如果它需要另一个重载,则需要这种转换。

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


1)

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

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

【讨论】:

  • 感谢标准的链接和 bool 的包装器也是一个有用的提示。
  • 我当时引用了错误的标准文本,并认为我的答案非常复杂。我认为为wchar_t const* 添加超载会更好。现在请随意给 Mark-Ransom 打勾,他基本上也是这么说的。
  • 现在,从 C++17 开始,我将删除第一个并替换为:void setValue( std::wstring_view name, std::wstring_view value ); template &lt;class T&gt; auto setValue(std::wstring_view name, T&amp;&amp; value) -&gt; decltype(std::wstring_view(value), void()) { setValue(name, std::wstring_view(value); }
【解决方案2】:

L"" 是指向宽字符串的指针。编译器认为转换为 bool 优先于转换为 std::wstring。

为了解决这个问题,引入一个新的 setValue:

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

【讨论】:

  • 不完全是。 L"" 是宽字符串文字。
【解决方案3】:

由于 bool 是内置类型,因此最好将 wchar_t 转换为 bool。我想说最简单的解决方案是添加一个重载,该重载采用 wchar_t 数组并在其中显式转换:

setValue( const std::wstring& name, const wchar_t s[] )
{
     setValue(name, wstring(s));
}

【讨论】:

    【解决方案4】:

    为了简化一点,下面的代码

    #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 版本调用”。您确定您的代码仅因空字符串而失败吗?

    【讨论】:

    • 我们目前不使用字符串文字,除了空字符串。我相信你是对的,这与字符串为空无关。
    • 字符串字面量不需要为空,编译器总是更喜欢强制转换为 bool 来初始化字符串类。顺便说一句,我想我在 VC++ 2005 中看到了与“强制值为 bool”有关的警告。
    【解决方案5】:

    您可以使新函数采用 bool 以外的其他类型——也许只是 bool 的代理——它不能从文字字符串转换。但实际上我只是重命名布尔函数并完成它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-01
      • 1970-01-01
      • 2016-10-23
      • 2017-11-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多