トップ回答者
std::stringへのキャスト演算子

質問
-
Visual Studio 2008から2012へVisual C++のプログラムを移植しております。
しかし、Visual Studio 2012のVC++では下記のエラーが出てしまいます。(2008ではエラーにならない)
testofcasttostrstring.cpp(11): error C2440: '型キャスト' : 'CVariantData' から 'std::string' に変換できません。
コンストラクターはソース型を持てません、またはコンストラクターのオーバーロードの解決があいまいです。VC2008→VC2012で仕様が変わったのでしょうか?
CVariantData::operator std::string() const
で、std::stringにキャストする際のキャスト演算子のオーバーロードができたのですが、できなくなったのでしょうか。
呼出元を修正せずに、同様にキャストで変換できる方法はありますでしょうか。
教えてください。
よろしくお願いいたします。
#include "stdafx.h" #include "PropertyGridDataType.h" #include <windows.h> int _tmain(int argc, _TCHAR* argv[]) { std::string str1; std::string str2; str1 = (std::string)"aabbcc"; CVariantData val(str1); str2 = ((std::string)(val));//NG // str2 = val.operator std::string();//OK // str2 = static_cast<std::string>(val);//NG // str2 = val.GetString();//OK OutputDebugString(str2.c_str()); OutputDebugString((const TCHAR *)val);//OK return 0; }
#pragma once #include <string> class CStringData; class /*AFX_EXT_CLASS*/ CVariantData { private: CStringData* m_pData; void DeleteData(); public: CVariantData(); explicit CVariantData(/*[in]*/std::string const& value); CVariantData(/*[in]*/const CVariantData& value); ~CVariantData(); std::string GetString(); // // cast operator // operator const TCHAR*() const; operator std::string() const; };
#include "stdafx.h" #include "PropertyGridDataType.h" //==================== // class CStringData //==================== class CStringData { private: std::string m_strValue; public: CStringData(/*[in]*/std::string const& strValue) : m_strValue(strValue) { } virtual ~CStringData() { } const std::string& GetValue() const { return m_strValue; } }; ///////////////////////////////////////////////////////////////////////////// // CVariantData CVariantData::CVariantData(/*[in]*/std::string const& value) { m_pData = new CStringData( value ); } CVariantData::~CVariantData() { if ( m_pData != NULL ) delete m_pData; m_pData = NULL; } CVariantData::operator const TCHAR*() const { return ((CStringData*)m_pData)->GetValue().c_str(); } CVariantData::operator std::string() const { return ((CStringData*)m_pData)->GetValue(); } std::string CVariantData::GetString() { return ((CStringData*)m_pData)->GetValue(); }
以上
回答
すべての返信
-
(std::string)val と記述した場合にどう解釈されるかについて説明します。この式はExplicit type conversionの(1) C-style cast expressionです。a) const_castではありませんので、b) static_castと解釈されます。
static_cast<std::string>(val) はstatic_cast conversionで説明されていますが、変換可能な場合はコンストラクター式として扱われます。
std::string Temp(val) ですが、std::stringがコンストラクター引数として受け付けるものが複数あり、その中でconst char*とconst std::string&(とstd::string&&)についてはCVariantDataから暗黙の変換が可能なため、ambiguous conversionとなります。
ちなみにC++言語で明示的な変換演算子の呼び出しは val.operator std::string() と記述します(jzkeyさんの回答は間違っています)。その上で質問文「呼出元を修正せずに、同様にキャストで変換できる方法はありますでしょうか」に応えるには、変換の曖昧さを解消するほかありません。 operator const TCHAR*() const; を explicit operator const TCHAR*() const; とすることで暗黙の変換を認めないようし、それによりコンストラクター引数候補を一意にする方法があります。ただし、explicitキーワードに対応したのはVisual C++ 2013からであり、Visual C++ 2012ではこの方法は使えません。
なお、先に回答したように operator std::string() const; を operator const std::string&() const; と参照を返すようにするとVisual C++は通常のコンストラクター呼び出しよりもコピーコンストラクターの呼び出しを優先するようで?この方法であればVisual C++ 2008、2010、2012、2015でも通用します。ただしこれはVisual C++固有の動作であり根本解決ではありませんのでgcc / clang辺りではコンパイルエラーなのは変わりませんし、Visual C++についても将来のバージョンで問題となる可能性があります。(ちなみにVisual C++ 2015からclangが使用可能になっており、その場合しっかりエラーになります。)