none
std::stringへのキャスト演算子 RRS feed

  • 質問

  • 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();
    }
    
    

    以上

    2016年8月17日 7:02

回答

すべての返信

  • operator const std::string&() const;

    なら通りそうですね。

    • 回答としてマーク akisas 2016年8月18日 2:45
    2016年8月17日 7:50
  • str2 = static_cast<std::string&&>(val);


    jzkey

    2016年8月17日 8:05
  • //CVariantData::operator std::string() const
    CVariantData::operator const std::string&() const
    {
    	return ((CStringData*)m_pData)->GetValue();
    }
    
    //	operator std::string() const;
    	operator const std::string&() const;
    

    これでできました。

    ありがとうございます。>ALL


    2016年8月18日 2:45
  • (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が使用可能になっており、その場合しっかりエラーになります。)

    2016年8月18日 3:00
  • ありがとうございます。

    勉強になります。

    2016年8月23日 6:04