Search code examples
c++mfcc++20atlvisual-studio-2022

Unable to use CA2CT and CW2T in Visual Studio 2022 when C++20 is specified


I am having a problem trying to use C++20 with Visual Studio 2022:

For example:

  • CA2CT
  • CW2T
  • CA2W

error C2440: 'initializing': cannot convert from ATL::CA2W to ATL::CStringT<wchar_t,StrTraitMFC<wchar_t,ATL::ChTraitsCRT<wchar_t>>>

If I revert to C++17 it is fine.

Why is this?


Here is an example:

CLSID AppCLSID ; 
if (SUCCEEDED(::CLSIDFromProgID(CT2W(rstrProgID), &AppCLSID) ) ) 
{
    LPOLESTR pszName = NULL ; 
    if (SUCCEEDED(::ProgIDFromCLSID(AppCLSID, &pszName) ) ) 
    {
        CString strAppID = CW2T(pszName); 
    }
}

Note that rStrProgId could be values like _T("Word.Application").

The above scpecific case the error is:

error C2440: 'initializing': cannot convert from ATL::CW2W to ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>


Other code snippets as examples:

Example 2

CString strCalendarName = CA2CT(pName->GetText(), CP_UTF8);

(the value of pName->GetText() is const char *).


Update

Doing what @Inspectable says resolves the one issue.

The others (examples) that won't compile are:

std::string s1 = CT2A(strNameText);
CString strStudent1 = CA2CT(pElement1->GetText(), CP_UTF8);

There are other compiling issues but I feel they are outside the scope of this question.


Solution

  • The issue evidently relates to /permissive- compiler option. If c++20 is selected, the compiler forces /permissive- option.

    /permissive- (Standards conformance)

    The /permissive- option is implicitly set by the /std:c++latest option starting in Visual Studio 2019 version 16.8, and in version 16.11 by the /std:c++20 option. /permissive- is required for C++20 Modules support.

    With /permissive- or /std:c++20 enabled, the compiler will not allow CStringA a = CW2A(L"123"); (I think because CW2A/CA2W use a conversion operator to return TCHAR* buffer to CString), so it needs {} initialization

    CStringA a { CW2A(L"123") };
    

    In this case it makes no difference with or without conformance, as far as I understand. But {} is preferred for initialization since c++11. For example it can check for narrowing conversion, and it's more consistent with other initialization forms:

    char c = 256;//compiles with warning, narrowing conversion
    char c {256};//won't compile
    char c[] = { 1,2 };//ok
    auto c {256};//compiles, auto -> int c
    auto c = {256};//std::initializer_list, cout << *c.begin();
    foo::foo(int i) : m_int{ i } {};//member initialization list
    RECT rc{};//set all members to zero