Reputation: 19087
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
toATL::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
toATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>
Other code snippets as examples:
CString strCalendarName = CA2CT(pName->GetText(), CP_UTF8);
(the value of pName->GetText()
is const char *)
.
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.
Upvotes: 6
Views: 2241
Reputation: 325
This is a somewhat more historic[ally known] issue methinks.
AFAIK this relates to
implicit handling of CString
classes (implicit operators: operator LPCTSTR()
etc. - e.g. as opposed to std::string
's likely intentionally explicit .c_str()
etc.).
[ Likely related topic: https://aras-p.info/blog/2008/10/09/implicit-to-pointer-operators-must-die/ ]
Which results in a required "double conversion" / "double transition" (sorry for inexact terms :( ) from RHS to LHS (CString
), which was sloppily accepted by MSVC all the time (like so much other annoying sloppy MSVC handling), yet which e.g. gcc for a long time (forever?) has been disallowing (likely due to language spec requirements), resulting in fail when trying to do certain transitions to CString
with gcc (better do NOT ask me how I know this 😔 ).
The issue here should be resolvable by doing
CString strAppID = static_cast<LPCTSTR>(CW2T(pszName));
or
CString strAppID = CW2T(pszName).m_psz;
(BTW which one is better?
.m_psz
is implementation details (specific member) but interestingly T-agnosticstatic_cast<LPCTSTR>
is non-implementation-specific but T-specific)
Though, as commented elsewhere, these are source changes (potentially many) required for this C++ spec change switch. Though this is the quite usual business of making existing [imperfectly precise] code fit for other (usually more strict/precise) specs/environments.
Upvotes: 1
Reputation: 31599
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 forC++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
Upvotes: 5