Question

CString est assez pratique, tandis que std::string est plus compatible avec le conteneur STL. J'utilise hash_map. Cependant, wstring ne prend pas en charge std::wstring la clé, je souhaite donc convertir <=> en <=>.

L'écriture d'une <=> fonction de hachage semble prendre beaucoup de temps.

CString -----> std::string

Comment puis-je faire cela?

std::string -----> CString:

inline CString toCString(std::string const& str)
{
    return CString(str.c_str()); 
}

Ai-je raison?

EDIT:

Voici d'autres questions:

Comment puis-je convertir <=>, <=> les uns aux autres?

//wstring -> CString,
std::wstring src;
CString result(src.c_str());
//CString->wstring. 
CString src;
::std::wstring des(src.GetString());

Existe-t-il un problème ?

Comment puis-je convertir <=>, <=> les uns aux autres?

Était-ce utile?

La solution

Selon CodeGuru :

CString à std::string:

CString cs("Hello");
std::string s((LPCTSTR)cs);

MAIS: LPCTSTR ne peut pas toujours construire à partir d'un LPSTR. le code échouera pour les versions UNICODE.

Comme LPCSTR ne peut construire qu'à partir de CT2CA / CStringT, un programmeur utilisant VC ++ 7.x ou une version supérieure peut utiliser des classes de conversion telles que char* en tant qu'intermédiaire.

CString cs ("Hello");
// Convert a TCHAR string to a LPCSTR
CT2CA pszConvertedAnsiString (cs);
// construct a std::string using the LPCSTR input
std::string strStd (pszConvertedAnsiString);

wchar_t* à LPWSTR : (De FAQ sur CString de Visual Studio. .. )

std::string s("Hello");
CString cs(s.c_str());

CStringA peut construire à partir de chaînes de caractères ou de chaînes de caractères larges. c'est-à-dire qu'il peut convertir à partir de wchar_t (c'est-à-dire CStringW) ou de TCHAR (char).

En d'autres termes, la spécialisation (de NUL), c'est-à-dire <=>, <=> - spécification <=>, et <=> - spécialisation <=> peut être construite à partir de <=> ou large- character, null terminé (les terminaisons null sont très importantes ici) sources de chaînes.
Althoug IInspectable modifie la & Quot; null-résiliation & Quot; partie dans les commentaires :

  

La terminaison NUL n'est pas requise .
  <=> a des constructeurs de conversion qui prennent un argument de longueur explicite. Cela signifie également que vous pouvez construire <=> des objets à partir de <=> objets avec des <=> caractères incorporés.

Autres conseils

Résolvez-le en utilisant std::basic_string<TCHAR> au lieu de std::string et tout devrait bien se passer, quel que soit le type de caractère que vous choisissez.

Il est plus efficace de convertir CString en std::string en utilisant la conversion où la longueur est spécifiée.

CString someStr("Hello how are you");
std::string std(somStr, someStr.GetLength());

En boucle serrée, cela améliore considérablement les performances.

Si vous voulez quelque chose de plus C ++, c'est ce que j'utilise. Bien que cela dépende de Boost, ce n'est que des exceptions. Vous pouvez facilement supprimer ceux qui le quittent pour qu'ils ne dépendent que de la STL et de WideCharToMultiByte() l'appel d'API Win32.

#include <string>
#include <vector>
#include <cassert>
#include <exception>

#include <boost/system/system_error.hpp>
#include <boost/integer_traits.hpp>

/**
 * Convert a Windows wide string to a UTF-8 (multi-byte) string.
 */
std::string WideStringToUtf8String(const std::wstring& wide)
{
    if (wide.size() > boost::integer_traits<int>::const_max)
        throw std::length_error(
            "Wide string cannot be more than INT_MAX characters long.");
    if (wide.size() == 0)
        return "";

    // Calculate necessary buffer size
    int len = ::WideCharToMultiByte(
        CP_UTF8, 0, wide.c_str(), static_cast<int>(wide.size()), 
        NULL, 0, NULL, NULL);

    // Perform actual conversion
    if (len > 0)
    {
        std::vector<char> buffer(len);
        len = ::WideCharToMultiByte(
            CP_UTF8, 0, wide.c_str(), static_cast<int>(wide.size()),
            &buffer[0], static_cast<int>(buffer.size()), NULL, NULL);
        if (len > 0)
        {
            assert(len == static_cast<int>(buffer.size()));
            return std::string(&buffer[0], buffer.size());
        }
    }

    throw boost::system::system_error(
        ::GetLastError(), boost::system::system_category);
}

(Depuis VS2012 ... et au moins jusqu'à VS2017 v15.8.1)

Puisqu'il s'agit d'un projet MFC & amp; CString est une classe MFC, MS fournit une note technique TN059: Utilisation de MFC MBCS / Unicode Macros de conversion et macros de conversion génériques:

A2CW      (LPCSTR)  -> (LPCWSTR)  
A2W       (LPCSTR)  -> (LPWSTR)  
W2CA      (LPCWSTR) -> (LPCSTR)  
W2A       (LPCWSTR) -> (LPSTR)  

Utiliser:

void Example() // ** UNICODE case **
{
    USES_CONVERSION; // (1)

    // CString to std::string / std::wstring
    CString strMfc{ "Test" }; // strMfc = L"Test"
    std::string strStd = W2A(strMfc); // ** Conversion Macro: strStd = "Test" **
    std::wstring wstrStd = strMfc.GetString(); // wsrStd = L"Test"

    // std::string to CString / std::wstring
    strStd = "Test 2";
    strMfc = strStd.c_str(); // strMfc = L"Test 2"
    wstrStd = A2W(strStd.c_str()); // ** Conversion Macro: wstrStd = L"Test 2" **

    // std::wstring to CString / std::string 
    wstrStd = L"Test 3";
    strMfc = wstrStd.c_str(); // strMfc = L"Test 3"
    strStd = W2A(wstrStd.c_str()); // ** Conversion Macro: strStd = "Test 3" **
}

-

Notes de bas de page:

(1) Pour que les macros de conversion disposent d'un espace pour stocker la longueur temporaire, il est nécessaire de déclarer une variable locale appelée _convert qui le fait dans chaque fonction utilisant les macros de conversion. Ceci est fait en appelant la macro USES_CONVERSION. Dans le code MFC VS2017 (atlconv.h), il ressemble à ceci:

#ifndef _DEBUG
    #define USES_CONVERSION int _convert; (_convert); UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/; (_acp); LPCWSTR _lpw; (_lpw); LPCSTR _lpa; (_lpa)
#else
    #define USES_CONVERSION int _convert = 0; (_convert); UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/; (_acp); LPCWSTR _lpw = NULL; (_lpw); LPCSTR _lpa = NULL; (_lpa)
#endif

Ceci fait suite à la réponse de Sal dans laquelle il a fourni la solution:

CString someStr("Hello how are you");
std::string std(somStr, someStr.GetLength());

Ceci est utile également lors de la conversion d'une C-String non typique en std :: string

Un cas d'utilisation pour moi était d'avoir un tableau de caractères pré-alloué (comme C-String), mais il n'est pas terminé par NUL. (c'est-à-dire SHA Digest). La syntaxe ci-dessus me permet de spécifier la longueur du résumé SHA du tableau de caractères de sorte que std :: string ne doive pas rechercher le caractère de fin NUL, qui peut être ou ne pas être là.

Tels que:

unsigned char hashResult[SHA_DIGEST_LENGTH];    
auto value = std::string(reinterpret_cast<char*>hashResult, SHA_DIGEST_LENGTH);

Cela fonctionne bien:

//Convert CString to std::string
inline std::string to_string(const CString& cst)
{
    return CT2A(cst.GetString());
}

de ce message ( Mark Ransom )

Convertir CString en chaîne (VC6)

J'ai testé cela et cela fonctionne bien.

std::string Utils::CString2String(const CString& cString) 
{
    std::string strStd;

    for (int i = 0;  i < cString.GetLength();  ++i)
    {
        if (cString[i] <= 0x7f)
            strStd.append(1, static_cast<char>(cString[i]));
        else
            strStd.append(1, '?');
    }

    return strStd;
}

Fonctionne pour moi:

std::wstring CStringToWString(const CString& s)
{
    std::string s2;
    s2 = std::string((LPCTSTR)s);
    return std::wstring(s2.begin(),s2.end());
}

CString WStringToCString(std::wstring s)
{
    std::string s2;
    s2 = std::string(s.begin(),s.end());
    return s2.c_str();
}

Toutes les autres réponses n'abordaient pas tout à fait ce que je cherchais, à savoir convertir CString à la volée au lieu de stocker le résultat dans une variable.

La solution est similaire à celle ci-dessus, mais nous avons besoin d’une étape supplémentaire pour instancier un objet sans nom. Je suis illustrant avec un exemple. Voici ma fonction qui nécessite std::string mais j'ai <=>.

void CStringsPlayDlg::writeLog(const std::string &text)
{
    std::string filename = "c:\\test\\test.txt";

    std::ofstream log_file(filename.c_str(), std::ios_base::out | std::ios_base::app);

    log_file << text << std::endl;
}

Comment l'appeler quand vous avez un <=>?

std::string firstName = "First";
CString lastName = _T("Last");

writeLog( firstName + ", " + std::string( CT2A( lastName ) ) );     

Notez que la dernière ligne n'est pas un transtypage direct, mais nous créons un objet sans nom <=> et fournissons le <=> via son constructeur.

  

Existe-t-il un problème ?

Il existe plusieurs problèmes:

  • CString est une spécialisation de modèle de CStringT . Selon le BaseType décrivant le type de caractère, il existe deux spécialisations concrètes: CStringA (utilisant char) et CStringW (utilisant wchar_t).
  • Alors que _UNICODE sur Windows est utilisé de manière omniprésente pour stocker des unités de code codées UTF-16, l'utilisation de std::string est ambiguë. Ce dernier stocke généralement les caractères encodés en ANSI, mais peut également stocker des données ASCII, UTF-8 ou même binaires.
  • Nous ne connaissons pas l'encodage des caractères (ni même le type de caractère) de std::wstring (contrôlé par le symbole du préprocesseur <=>), ce qui rend la question ambiguë. Nous ne connaissons pas non plus le codage de caractères souhaité de <=>.
  • La conversion entre Unicode et ANSI entraîne des pertes inhérentes: le codage ANSI ne peut représenter qu'un sous-ensemble du jeu de caractères Unicode.

Pour résoudre ces problèmes, je suppose que <=> stockera les unités de code codées UTF-16 et <=> conservera les séquences d'octets UTF-8. C’est le seul choix raisonnable que vous pouvez faire pour vous assurer que les chaînes source et cible conservent les mêmes informations, sans limiter la solution à un sous-ensemble des domaines source ou cible.

Les implémentations suivantes convertissent entre <=> / <=> et <=> / <=> le mappage de UTF-8 à UTF-16 et inversement:

#include <string>
#include <atlconv.h>

std::string to_utf8(CStringW const& src_utf16)
{
    return { CW2A(src_utf16.GetString(), CP_UTF8).m_psz };
}

std::wstring to_utf16(CStringA const& src_utf8)
{
    return { CA2W(src_utf8.GetString(), CP_UTF8).m_psz };
}

Les deux fonctions restantes construisent des objets chaîne C ++ à partir de chaînes MFC, en laissant le codage inchangé. Notez que bien que les fonctions précédentes ne puissent pas gérer les caractères NUL intégrés, ces fonctions sont immunisées contre cela.

#include <string>
#include <atlconv.h>

std::string to_std_string(CStringA const& src)
{
    return { src.GetString(), src.GetString() + src.GetLength() };
}

std::wstring to_std_wstring(CStringW const& src)
{
    return { src.GetString(), src.GetString() + src.GetLength() };
}

Vous pouvez utiliser CT2CA

CString datasetPath;
CT2CA st(datasetPath);
string dataset(st);

Si vous cherchez à convertir facilement entre d'autres types de chaînes, le _bstr_t serait plus approprié? Il prend en charge les conversions entre char, wchar_t et BSTR.

Une approche intéressante consiste à transtyper CString en CStringA à l'intérieur d'un constructeur string. Contrairement à std::string s((LPCTSTR)cs);, cela fonctionnera même si _UNICODE est défini. Toutefois, si tel est le cas, la conversion d'Unicode à ANSI sera effectuée. Par conséquent, la sécurité des valeurs Unicode supérieures au-delà du jeu de caractères ASCII n'est pas sûre. Cette conversion est soumise à la _CSTRING_DISABLE_NARROW_WIDE_CONVERSION définition du préprocesseur. https://msdn.microsoft.com/en-us/library/5bzxfsea. aspx

        CString s1("SomeString");
        string s2((CStringA)s1);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top