【问题标题】:Is it possible to initialise a character array with a conditionally selected string literal?是否可以使用有条件选择的字符串文字来初始化字符数组?
【发布时间】:2015-01-23 16:26:26
【问题描述】:

我知道用字符串字面量初始化 char 数组是完全可能的:

char arr[] = "foo";

C++11 8.5.2/1 这么说:

char 数组(无论是普通的 charsigned char 还是 unsigned char)、char16_t 数组、char32_t 数组,或 wchar_t 数组可以用窄字符字面量初始化,char16_t 字符串字面量,char32_t 字符串 文字或宽字符串文字,或用括号括起来的适当类型的字符串文字。 字符串文字值的连续字符初始化数组的元素。 ...

但是,您可以在条件表达式中对 两个 字符串文字做同样的事情吗?比如这样:

char arr[] = MY_BOOLEAN_MACRO() ? "foo" : "bar";

(其中MY_BOOLEAN_MACRO() 扩展为10)。

C++11 5.16(条件运算符)的相关部分如下:

1 ... 第一个表达式根据上下文转换为bool(第 4 条)。 它被求值,如果是true,条件表达式的结果就是第二个表达式的值, 否则是第三个表达式。 ...

4 如果第二个和第三个操作数是相同值类别的glvalues并且具有相同的类型,则结果 属于该类型和值类别,并且如果第二个或第三个操作数是位域,或者如果 两者都是位域。

请注意,文字的长度相同,因此它们都是 const char[4] 类型的左值。

GCC one ideone 接受构造。但是通过阅读标准,我根本不确定它是否合法。有没有人有更好的见解?

【问题讨论】:

    标签: c++ language-lawyer string-literals


    【解决方案1】:

    另一方面,clang 不接受这样的代码 (see it live),我相信 clang 对此是正确的 (MSVC also rejects this code )。

    字符串字面量2.14.5部分的语法定义:

    string-literal:
        encoding-prefixopt" s-char-sequenceopt"
        encoding-prefixoptR raw-string
    

    本节的第一段说(强调我的):

    字符串字面量是一个字符序列(定义见 2.14.3) 双引号括起来,可选前缀为 R, u8, u8R, u, uR, U、UR、L 或 LR,如 "..."、R"(...)"、u8"..."、u8R"(...)"、 u"...", uR"~(...)~", U"...", UR"zzz(...)zzz", L"...",或 LR"(...)", 分别

    它进一步说窄字符串文字的类型是:

    “n const char 数组”,

    还有:

    具有静态存储持续时间

    但是具有静态存储持续时间的“n const char 数组”, 不是字符串文字,因为它不符合语法也不符合段落@987654329 @。

    如果我们使用非常量表达式 (see it live),我们可以在 gcc 上失败:

    bool x = true ;
    char arr[] = x ? "foo" : "bar";
    

    这意味着它可能是一个扩展,但它不符合标准,因为它不会在strict conformance mode 中产生警告,即使用-std=c++11 -pedantic。来自1.4部分[intro.compliance]

    [...]需要实现来诊断使用此类的程序 根据本国际格式不正确的扩展 标准。然而,这样做之后,他们可以编译和执行这样的 程序。

    【讨论】:

    • 同意,8.5.2/1 似乎很清楚它是字符串文字,而不是某个计算结果为字符串文字的表达式。 (即使您认为在这种情况下三元运算符评估为字符串文字)。
    【解决方案2】:

    这适用于 GCCC++11 或更新版本,因为您提供的文字在编译时是确定的(例如,它们是 constexpr)。既然编译器可以判断出哪一个是真的,那么就可以判断使用哪一个了。

    要移除constexpr 功能,请尝试以下操作:

    #include <iostream>
    #include <cstdlib>
    
    int main() {
        bool _bool = rand();
        char arr[] = (_bool) ? "asdf" : "ffff";
    
        std::cout << arr << std::endl;
    }
    

    GCC 然后出错:

    g++ test.cpp -std=c++11
    test.cpp: In function ‘int main()’:
    test.cpp:6:34: error: initializer fails to determine size of ‘arr’
      char arr[] = (_bool) ? "asdf" : "ffff";
                                      ^
    test.cpp:6:34: error: array must be initialized with a brace-enclosed initializer
    

    我不太了解标准的文本定义,无法知道它在哪里或为什么有效,但我感觉有效的。

    如需进一步了解constexpr 以及它如何影响可编译性,请参阅the answer by @ShafikYaghmour in another question

    【讨论】:

    • 请注意,constant expressionconstexpr 相关但不相同,我在某种程度上涵盖了 here 所以 gcc 正在处理它作为一个常量表达式。
    • 没错,我可以看到有区别。但这是一个很好的观点,我认为差异不适用于 c++11 及更高版本......除非你能证明它确实如此?
    • 仅供参考,希望对您有所帮助。我只想指出,由于问题被标记为语言律师,因此人们往往对细节更加挑剔。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-14
    • 2021-08-26
    • 1970-01-01
    • 2011-12-11
    • 1970-01-01
    • 2016-11-12
    相关资源
    最近更新 更多