指定C++20时无法在Visual Studio 2022中使用CA2CT和CW2T

vbopmzt1  于 2023-01-28  发布在  其他
关注(0)|答案(2)|浏览(409)

我在尝试将C++20与Visual Studio 2022配合使用时遇到问题:
例如:

  • CA2CT
  • CW2T
  • CA2W

错误C2440:"正在初始化":无法从ATL::CA2W转换为ATL::CStringT<wchar_t,StrTraitMFC<wchar_t,ATL::ChTraitsCRT<wchar_t>>>
如果我恢复到C++17就可以了。
这是为什么呢?
下面是一个例子:

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

请注意,rStrProgId可以是类似_T("Word.Application")的值。
上述特定情况下的错误为:
错误C2440:"正在初始化":无法从ATL::CW2W转换为ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>
其他代码片段作为示例:

示例2

CString strCalendarName = CA2CT(pName->GetText(), CP_UTF8);
(the pName->GetText()的值为const char *)

更新

做@Inspectable所说的事情可以解决一个问题。
其他无法编译的示例有:

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

还有其他编译问题,但我觉得它们超出了这个问题的范围。

fjaof16o

fjaof16o1#

此问题显然与/permissive-编译器选项有关。如果选择c20,则编译器强制/permissive-选项。
/permissive- (Standards conformance)
从Visual Studio 2019版本16.8开始,/permissive-选项由/std:c
最新选项隐式设置,在版本16.11中由/std:c++20选项隐式设置。C++20模块支持需要/permissive-
启用/permissive-/std:c++20后,编译器将不允许CStringA a = CW2A(L"123");(我认为是因为CW2A/CA2W使用转换操作符将TCHAR*缓冲区返回到CString),因此需要初始化{}

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

在这种情况下,就我的理解,一致性和不一致性没有什么区别,但是从c++11开始,{}是初始化的首选,例如它可以检查收缩转换,并且它与其他初始化形式更加一致:

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
xzlaal3s

xzlaal3s2#

我认为这是一个更有历史意义的问题。AFAIK这涉及到CString类的隐式处理(隐式操作符:operator LPCTSTR()等例如与std::string的可能有意显式的.c_str()等相反)。
[可能相关的主题:网站]https://aras-p.info/blog/2008/10/09/implicit-to-pointer-operators-must-die/ ]
这导致了一个必需的"双重转换"/"双重转换"(很抱歉用了不确切的术语:()从RHS到LHS(CString),MSVC一直草率地接受它(就像许多其他令人讨厌的草率的MSVC处理一样),然而,例如gcc很长一段时间(永远?)一直不允许(可能是由于语言规范的要求),导致在尝试使用gcc进行某些到CString的转换时失败(最好不要问我是如何知道的)。这里的问题应该可以通过以下操作解决😔 ). The issue here should be resolvable by doing

CString strAppID = static_cast<LPCTSTR>(CW2T(pszName));

CString strAppID = CW2T(pszName).m_psz;

(BTW哪个比较好?

  • .m_psz是实现细节(特定成员),但有趣的是它与T无关
  • static_cast<LPCTSTR>不特定于实现,但特定于T


尽管如此,正如其他地方所评论的,这些都是C++规范更改开关所需的源代码更改(可能很多),尽管这是使现有的[不完全精确的]代码适合其他(通常更严格/精确的)规范/环境的相当常见的事情。

相关问题