是否可以使用有条件选择的字符串文字来初始化字符数组?

Is it possible to initialise a character array with a conditionally selected string literal?

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

char arr[] = "foo";

C++11 8.5.2/1 是这样说的:

A char array (whether plain char, signed char, or unsigned char), char16_t array, char32_t array, or wchar_t array can be initialized by a narrow character literal, char16_t string literal, char32_t string literal, or wide string literal, respectively, or by an appropriately-typed string literal enclosed in braces. Successive characters of the value of the string literal initialize the elements of the array. ...

但是,您可以对条件表达式中的 两个 字符串文字执行相同的操作吗?例如像这样:

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

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

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

1 ... The first expression is contextually converted to bool (Clause 4). It is evaluated and if it is true, the result of the conditional expression is the value of the second expression, otherwise that of the third expression. ...

4 If the second and third operands are glvalues of the same value category and have the same type, the result is of that type and value category and it is a bit-field if the second or the third operand is a bit-field, or if both are bit-fields.

注意文字的长度相同,因此它们都是 const char[4].

类型的左值

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

另一方面 clang 不接受这样的代码 (see it live) and I believe clang is correct on this (MSVC also rejects this code )。

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

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

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

A string literal is a sequence of characters (as defined in 2.14.3) surrounded by double quotes, optionally prefixed by R, u8, u8R, u, uR, U, UR, L, or LR, as in "...", R"(...)", u8"...", u8R"(...)", u"...", uR"˜(...)˜", U"...", UR"zzz(...)zzz", L"...", or LR"(...)", respectively

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

“array of n const char”,

以及:

has static storage duration

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

如果我们使用非常量表达式 (see it live):

,我们可以在 gcc 上使它失败
bool x = true ;
char arr[] = x ? "foo" : "bar";

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

[...]Implementations are required to diagnose programs that use such extensions that are ill-formed according to this International Standard. Having done so, however, they can compile and execute such programs.

这适用于 GCC C++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