コンパイラが、L””の暗黙の型キャストのために文字列よりブールを選択するのはなぜですか?
-
11-07-2019 - |
質問
最近、アプリケーションが失敗し始めたメソッドのオーバーロードを導入しました。 最後にそれを追跡し、新しいメソッドが呼び出されると予想していなかった場所で呼び出されています。
持っていた
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&quot;&quot;の問題それは暗黙的にキャストしていることであり、以前はstd :: wstringであったことが幸福でしたが、boolを好むわけではありません。 MSVCコンパイラーは文句を言わないか、警告を発しませんので、「修正」したとしても心配です。 setValue(L&quot; empty&quot ;, L&quot;&quot;);あるべき
setValue( L"empty", std::wstring() );
他の誰かが後で来て、単にsetValue(L&quot; empty&quot ;, L&quot;&quot;)を使用するかもしれません;この問題を再度追跡する必要があります。
メソッドで明示的に使用することを考えましたが、この使用法では有効なキーワードではありません。 コンパイラーにこれについて不平を言う、または問題を防ぐ方法はありますか?それ以外の場合は、boolを取るメソッドの名前を変更して、間違った推測ができないようにすることを考えています。
解決
まず、この問題の原因:C ++標準 [ over.ics.rank] /2.1
1 は、変換シーケンスの順序を定義します。ユーザー定義の変換シーケンスは、標準の変換シーケンスよりも悪いという。あなたの場合、文字列リテラルはブール変換( 4.12
で定義されます。これは標準の変換です)が行われます。ユーザー定義の std :: wstring
への変換は使用しません。これは、他のオーバーロードが必要な場合に必要になります。
オーバーロードの1つの名前を単に変更するか、文字列リテラルを直接受け入れるオーバーロードを追加することをお勧めします(パラメータータイプ wchar_t const *
を使用)。
1)
暗黙的な変換シーケンスの基本形式を比較する場合(
[over.best.ics]
で定義)(2.1)標準の変換シーケンスは、ユーザー定義の変換シーケンスまたは省略変換シーケンスよりも優れた変換シーケンスであり、
(2.2)ユーザー定義の変換シーケンスは、省略変換シーケンスよりも優れた変換シーケンスです。
他のヒント
L&quot;&quot;ワイド文字ストリングへのポインターです。コンパイラは、boolへの変換がstd :: wstringへの変換より優先されると考えています。
問題を修正するには、新しいsetValueを導入します:
void setValue(std::wstring const& name, const wchar_t * value);
boolは組み込み型であるため、wchar_tからboolへの変換が推奨されます。最も簡単な解決策は、wchar_t配列を受け取り、そこに明示的にキャストするオーバーロードを追加することです。
setValue( const std::wstring& name, const wchar_t s[] )
{
setValue(name, wstring(s));
}
少し簡略化するために、次のコード
#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"); }
&quot; bool と呼ばれるバージョンを印刷します&quot;。コードが空の文字列のみで失敗することを確認しますか?
新しい関数にbool以外の型(boolの単なるプロキシ)を使用させることができます。これはリテラル文字列から変換できません。しかし、実際には、bool-taking関数の名前を変更して、それで終わりです。