代码之家  ›  专栏  ›  技术社区  ›  Andrew Truckle

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

  •  0
  • Andrew Truckle  · 技术社区  · 3 年前

    我在尝试将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);

    (的值 pName->GetText() const char *) .


    使现代化

    按照@Inspectable所说的去做解决了一个问题。

    其他无法编译的(示例)有:

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

    还有其他编译问题,但我觉得它们不在这个问题的范围内。

    0 回复  |  直到 3 年前
        1
  •  5
  •   Barmak Shemirani    3 年前

    这个问题显然与 /permissive- 编译器选项。如果选择了c++20,编译器将强制 放任的 选项

    /permissive- (Standards conformance)

    这个 放任的 选项由/std:c++最新选项隐式设置 在Visual Studio 2019版本16.8中启动,在版本16.11中由 /std:c++20选项。 放任的 是的必需项 C++20 模块 支持

    具有 放任的 /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
    
        2
  •  0
  •   Andrew Truckle    1 年前

    我认为这是一个更具历史意义的问题。 AFAIK这与 的隐含处理 CString 类(隐式运算符: operator LPCTSTR() 等等-例如,与 std::string 很可能是故意明确的 .c_str()

    [ 可能相关的主题: https://aras-p.info/blog/2008/10/09/implicit-to-pointer-operators-must-die/ ]

    这导致了从RHS到LHS所需的“双重转换”/“双重转变”(抱歉使用了不精确的术语:()( C字符串 ),它一直被MSVC草率地接受(就像许多其他令人讨厌的草率MSVC处理一样),但它(例如gcc)在很长一段时间内(永远?)一直被禁止(可能是由于语言规范要求),导致在尝试进行某些转换时失败 C字符串 使用gcc(最好不要问我是怎么知道的)。 这里的问题应该通过做来解决

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

    CString strAppID = CW2T(pszName).m_psz;
    

    (顺便问一下,哪一个更好?

    • .m_psz 是实现细节(特定成员),但有趣的是T不可知
    • static_cast<LPCTSTR> 不是特定于实现,而是特定于T

    )

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