【问题标题】:C++17 conditional (ternary) operator inconsistency between MSVC and Clang/GCCMSVC 和 Clang/GCC 之间的 C++17 条件(三元)运算符不一致
【发布时间】:2021-08-22 20:40:50
【问题描述】:

以下代码在 C++17 标准下的 Clang/GCC 下编译,但在带有 -std:C++17 /Zc:ternary 的 MSVC 下无法编译。

struct CStringPtr
{
    const char *m_pString = nullptr;

    CStringPtr() = default;
    CStringPtr( const char *pString ) : m_pString( pString ) { }

    operator const char *() const { return m_pString; }
};

int main( int argc, char ** )
{
    bool b = !!argc;

    const char *X = b ? CStringPtr( "inside" ) : "naked";
    const char *Y = b ? "naked" : CStringPtr( "inside" );
    CStringPtr Z = b ? CStringPtr( "inside" ) : "naked";
    CStringPtr W = b ? "naked" : CStringPtr( "inside" );

    // Silence unused-variable warnings.
    return X && Y && Z && W;
}

三个链接到 Godbolt 的编译器资源管理器:https://godbolt.org/z/6d5Mrjnd7

MSVC 为这四行中的每一行发出一个错误:

<source>(19): error C2445: result type of conditional expression is ambiguous: types 'const char [6]' and 'CStringPtr' can be converted to multiple common types
<source>(19): note: could be 'const char *'
<source>(19): note: or       'CStringPtr'

而对于所有这四种情况,Clang/GCC 都为裸字符串调用 CStringPtr 构造函数。

MSVC /Zc:ternary documentation 中,他们声称该标志启用了三元运算符的符合标准的解析,这意味着 MSVC 的实现中存在错误或 Clang/GCC 在此处不符合标准。

这里的另一个注意事项是,MSVC 文档在这种确切的情况下提到了一个关于正在使用的 const char * 类型的异常:

这种常见模式的一个重要例外是当操作数的类型是空终止字符串类型之一时,例如 const char*、const char16_t* 等。您还可以使用数组类型和它们衰减到的指针类型来重现效果。 ?: 的实际第二个或第三个操作数是相应类型的字符串文字时的行为取决于所使用的语言标准。 C++17 已从 C++14 更改了此案例的语义。

那么,MSVC 不符合 C++17 规则吗?还是 Clang/GCC?

【问题讨论】:

    标签: c++ visual-c++ c++17 language-lawyer


    【解决方案1】:

    这是Core issue 1805,它将?: 更改为将数组和函数衰减为指针,然后再测试其他操作数是否可以转换为它。该问题中的示例基本上是您问题中的示例:

      struct S {
        S(const char *s);
        operator const char *();
      };
    
      S s;
      const char *f(bool b) {
        return b ? s : "";   // #1
      }
    

    人们可能会认为#1 中的表达式会模棱两可,因为 S 可以与const char* 相互转换。然而 s 转换的目标类型是const char[1],而不是const char*,所以转换失败,结果 条件表达式的类型为S

    似乎 GCC 和 Clang 都没有实现该问题的解决方案,因此他们仍在测试 CStringPtr 是否可以转换为数组。

    如果您使用一元 + 手动衰减字符串文字,则每个人都拒绝该示例为模棱两可。

    【讨论】:

      猜你喜欢
      • 2014-04-11
      • 2021-09-18
      • 1970-01-01
      • 2017-03-02
      • 1970-01-01
      • 2020-12-22
      • 1970-01-01
      • 2010-10-20
      • 1970-01-01
      相关资源
      最近更新 更多