VC++ で マルチバイト文字列とワイド文字列を簡単に変換するライブラリを作ってみた


## 1. はじめに

  Visual C++ 環境でプログラムしていると `std::string`, `std::wstring`, `CStringA`, `CStringW` を使う場面が出てくる。 これらを変換させる個別の関数を作って呼び出していたが 場合分けが 煩わしいので、単純に代入できるクラスを作ってみた。
以下の様な感じで `kstring()` を介せば型を気にせず代入可能。

```C++
main()
{
    string    a ;
    wstring   b ;
    CStringA  c ;
    CStringW  d ;
    
    a = kstring(b) ; a = kstring(c) ; a = kstring(d) ;
    b = kstring(a) ; b = kstring(c) ; b = kstring(d) ;
    c = kstring(a) ; c = kstring(b) ; c = kstring(d) ;
    d = kstring(a) ; d = kstring(b) ; d = kstring(c) ;
```

## 2. 概要

`std::string` を継承する  `kstring`クラス と  `std::wstring` を継承する `kwstring`クラスを作って、各型からのコンストラクタと 各型へのキャストを定義する。

## 3. ベースとなる単方向の変換関数
### (1) `string` → `wstring` 
```C++
inline std::wstring str_to_wstr(std::string const& src)
{
    vector<wchar_t> dest( src.length()+16 ) ;
    std::size_t converted ;
    ::mbstowcs_s( &converted, dest.data(), dest.size(), src.c_str(), _TRUNCATE ) ;
    return std::wstring( dest.data() ) ;
}
```
### (2)  `wstring` → `string`

```C++
inline std::string wstr_to_str(std::wstring const& src)
{
    vector<char> dest( src.length()+16 ) ;
    std::size_t converted ;
    ::wcstombs_s( &converted, dest.data(), dest.size(), src.c_str(), _TRUNCATE ) ;
    return std::string( dest.data() ) ;
}
```
## 4. 変換用のクラス

煩雑になるので `CStringA`と `CStringW` は後ほど追加。まずは `string` と `wstring`。

### (1) `string` の継承クラス `kstring` を定義
`kstring` に対し、`string`, `wstring`, `kwstring` とのコンストラクタと キャストを定義。


```C++
class kwstring ;	// wstring の継承クラス

class kstring : public std::string
{
public:
    kstring() = default ;

    kstring(const string &str) : string(str) { }

    kstring(const wstring &wstr)
    {
        *(string*)this = wstr_to_str( wstr ) ;
    }

    // kwstring 定義後に記述
    inline kstring(const kwstring &kwstr) ;

public:
    operator string()
    {
        return *(string*)this ;
    }

    operator wstring()
    {
        return str_to_wstr( *this ) ;
    }

    // kwstring 定義後に記述
    inline operator kwstring() ;
} ;
```

kstring の kwstring参照部分の定義で、kwstring の後に記述する

```C++
inline kstring::kstring(const kwstring &kwstr)
{
    *(string*)this = wstr_to_str( kwstr ) ;
}

inline kstring::operator kwstring()
{
    return str_to_wstr(*this) ;
}
```

### (2) `wstring` の継承クラス
`kwstring` に対し、`string`, `wstring`, `kstring` とのコンストラクタと キャストを定義。

```C++
class kwstring : public std::wstring
{
public:
    kwstring() = default ;

    kwstring(const wstring &wstr) : wstring(wstr) { }

    kwstring(const string &str)
    {
        *(wstring*)this = str_to_wstr( str ) ;
    }

    kwstring(const kstring &kstr)
    {
        *(wstring*)this = str_to_wstr( kstr ) ;
    }

public:
    operator wstring()
    {
        return *(wstring*)this ;
    }

    operator string()
    {
        return wstr_to_str( *(wstring*)this ) ;
    }

    operator kstring()
    {
        return wstr_to_str(*this) ;
    }
} ;
```
## 5. CStringA と CStringW に対応

`CStringA` と `CStringW` は相互代入が可能なのでこれを利用

### (1) kstringを拡張する
`kstring` に対し、`CStringA`, `CStringW` とのコンストラクタと キャストを定義。

```C++
    kstring(const CStringA &str)
    {
        *(string*)this = (char*)(LPCSTR)str ;
    }

    kstring(const CStringW &strw)
    {
        *(string*)this = (char*)(LPCSTR)CStringA(strw) ;
    }

    operator CStringW()
    {
        return CStringW( CStringA(this->c_str()) );
    }

    operator CStringA()
    {
        return CStringA( this->c_str() ) ;
    }
```

### (2) kwstringを拡張する
`kwstring` に対し、`CStringA`, `CStringW` とのコンストラクタと キャストを定義。

```C++
    kwstring(const CStringW &strw)
    {
        *(wstring*)this = (wchar_t*)(LPCWSTR)strw ;
    }

    kwstring(const CStringA &str)
    {
        *(wstring*)this = (wchar_t*)(LPCWSTR)CStringW(str) ;
    }

    operator CStringW()
    {
        return CStringW( this->c_str() ) ;
    }

    operator CStringA()
    {
        return CStringA( this->c_str() ) ;
    }
```

## 6. おまけ
### (1) `kstring`, `kwstring` の出力定義
```C++
inline std::ostream & operator << (std::ostream& os, const kstring &str )
{
    os << string(str) ;
    return os ;
}

inline std::wostream & operator << (std::wostream& os, const kwstring &wstr )
{
    os << wstring(wstr) ;
    return os ;
}
```

### (2) `operator =` を定義すれば 汎用性が増すかな
```C++
    kstring & operator = (const wstring &wstr)
    {
        *(string*)this = wstr_to_str( wstr ) ;
        return *this ;
    }
```

### (3) Windows APIを使った変換
ベースとなる単方向の変換関数を Windows API を使って作った場合

```C++
inline std::wstring StringToWString( const std::string &src )
{
    vector<wchar_t> dest( src.length()+16 ) ;
    ::MultiByteToWideChar( CP_ACP, 0, src.c_str(), -1, dest.data() ,dest.size() );
    return std::wstring( dest.data() ) ;
}

inline std::string WStringToString( const std::wstring &src )
{
    vector<char> dest( src.length()+16 ) ;
    ::WideCharToMultiByte( CP_OEMCP, 0, src.c_str(), -1, dest.data() ,dest.size(), NULL, NULL );
    return std::string( dest.data() ) ;
}
```




## 7. ソース一括
```C++
#include <vector>
#include <iostream>
#include <cstring>
#include <atlstr.h>

using std::string ;
using std::wstring ;
using std::vector ;
using std::cout ;
using std::wcout ;
using std::endl ;

//-------------------------------------
inline std::wstring str_to_wstr(std::string const& src)
{
    vector<wchar_t> dest( src.length()+16 ) ;
    std::size_t converted ;
    ::mbstowcs_s( &converted, dest.data(), dest.size(), src.c_str(), _TRUNCATE ) ;
    return std::wstring( dest.data() ) ;
}

inline std::string wstr_to_str(std::wstring const& src)
{
    vector<char> dest( src.length()+16 ) ;
    std::size_t converted ;
    ::wcstombs_s( &converted, dest.data(), dest.size(), src.c_str(), _TRUNCATE ) ;
    return std::string( dest.data() ) ;
}

//-------------------------------------
class kwstring ;	// wstring の継承クラス

class kstring : public std::string
{
public:
    kstring() = default ;

    kstring(const string &str) : string(str) { }

    kstring(const wstring &wstr)
    {
        *(string*)this = wstr_to_str( wstr ) ;
    }

    inline kstring(const kwstring &kwstr) ;

public:
    operator string()
    {
        return *(string*)this ;
    }

    operator wstring()
    {
        return str_to_wstr( *this ) ;
    }

    inline operator kwstring() ;

public:
    kstring(const CStringA &str)
    {
        *(string*)this = (char*)(LPCSTR)str ;
    }

    kstring(const CStringW &strw)
    {
        *(string*)this = (char*)(LPCSTR)CStringA(strw) ;
    }

    operator CStringW()
    {
        return CStringW( CStringA(this->c_str()) );
    }

    operator CStringA()
    {
        return CStringA( this->c_str() ) ;
    }
} ;

//-------------------------------------
class kwstring : public std::wstring
{
public:
    kwstring() = default ;

    kwstring(const wstring &wstr) : wstring(wstr) { }

    kwstring(const string &str)
    {
        *(wstring*)this = str_to_wstr( str ) ;
    }

    kwstring(const kstring &kstr)
    {
        *(wstring*)this = str_to_wstr( kstr ) ;
    }

public:
    operator wstring()
    {
        return *(wstring*)this ;
    }

    operator string()
    {
        return wstr_to_str( *(wstring*)this ) ;
    }

    operator kstring()
    {
        return wstr_to_str(*this) ;
    }

public:
    kwstring(const CStringW &strw)
    {
        *(wstring*)this = (wchar_t*)(LPCWSTR)strw ;
    }

    kwstring(const CStringA &str)
    {
        *(wstring*)this = (wchar_t*)(LPCWSTR)CStringW(str) ;
    }

    operator CStringW()
    {
        return CStringW( this->c_str() ) ;
    }

    operator CStringA()
    {
        return CStringA( this->c_str() ) ;
    }
} ;

//-------------------------------------
inline kstring::kstring(const kwstring &kwstr)
{
    *(string*)this = wstr_to_str( kwstr ) ;
}

inline kstring::operator kwstring()
{
    return str_to_wstr(*this) ;
}

//-------------------------------------
inline std::ostream & operator << (std::ostream& os, const kstring &str )
{
    os << string(str) ;
    return os ;
}

inline std::wostream & operator << (std::wostream& os, const kwstring &wstr )
{
    os << wstring(wstr) ;
    return os ;
}

//-------------------------------------
int main()
{
    string    a =  "abc" ;
    wstring   b = L"ABC" ;
    CStringA  c =  "xyz" ;
    CStringW  d = L"XYZ" ;
    
    a = kstring(b) ; a = kstring(c) ; a = kstring(d) ;
    b = kstring(a) ; b = kstring(c) ; b = kstring(d) ;
    c = kstring(a) ; c = kstring(b) ; c = kstring(d) ;
    d = kstring(a) ; d = kstring(b) ; d = kstring(c) ;

    cout << kstring(b) << endl ;
    wcout << kstring(a) << endl ;

    return 0 ;
}
```