我可以用三元初始化一个 char[] 吗?
Can I Initialize a char[] with a Ternary?
我问 and didn't get a really clear answer, but after reading this article 我开始更喜欢 const char[]
而不是 const char*
。
我在用三元初始化时遇到了困难。鉴于 const bool bar
,我试过:
const char foo[] = bar ? "lorem" : "ipsum"
这给了我错误:
error: initializer fails to determine size of foo
const char foo[] = bar ? { 'l', 'o', 'r', 'e', 'm', '[=15=]' } : { 'i', 'p', 's', 'u', 'm', '[=15=]' }
这给了我错误:
error: expected primary-expression before {
token
有没有办法用三元初始化一个const char []
,或者我必须在这里切换到const char*
?
无法使用三元运算符初始化字符数组。这样做的原因是三元运算符的两边实际上都是用来构造一个对象的,而不是用来初始化对象的值的。由于您不能从一个数组初始化另一个数组,因此数组的三元初始化不起作用。
不过,如果您明确指定类型(并假设 C++17),它会用于 std::arrays
:
std::array k = b ? std::array{1, 2, 3, 4} : std::array{ 5, 6, 7 ,8};
请注意,数组的大小必须相同。在这种情况下根本无法使用不同大小的数组,因为三元运算符的两边必须是同一类型(并且数组的大小是其类型的一部分)。如果您的字符串大小不同,则必须使用 const char* const
.
由于字符串文字是左值,您可以对它们进行 const 引用,这可以在三元中使用。
// You need to manually specify the size
const char (&foo)[6] = bar ? "lorem" : "ipsum";
// Or (In C++11)
auto foo = bar ? "lorem" : "ipsum";
auto
的行为完全相同(除了您必须指定大小)。
如果你想对不同长度的字符串执行此操作,不幸的是“bool ? const char[x] : const char[y]
”只有在它们具有相同大小的情况下才会是数组类型(否则它们都会衰减为指针,并且表达式将是const char*
类型)。要解决此问题,您必须用 [=18=]
字符手动填充字符串(现在您不能执行 sizeof(foo) - 1
来获取大小,您必须执行 strlen(foo)
)。
例如,而不是:
auto foo = bar ? "abc" : "defg"; // foo is a const char*
你必须做的:
auto foo = bar ? "abc[=12=]" : "defg"; // foo is const char(&)[5]
// Note that if `bar` is true, foo is `{'a', 'b', 'c', '[=12=]', '[=12=]'}`
在您必须这样做之前,请考虑如果您将变量设置为 const char * const
,您的编译器很可能会将它们优化为与 const char[]
完全相同,并且如果您不更改值,如果它们只是 const char *
(末尾没有 const),也可能相同。
为了不意外地得到一个指针,并且如果你这样做很快就会失败,我会使用一个辅助函数:
#include <cstddef>
template<std::size_t size, std::size_t other_size = size>
constexpr auto conditional(bool condition, const char(&true_case)[size], const char(&false_case)[other_size]) noexcept -> const char(&)[size] {
static_assert(size == other_size, "Cannot have a c-string conditional with c-strings of different sizes");
return condition ? true_case : false_case;
}
// Usage:
auto foo = conditional(bar, "lorem", "ipsum");
如果bar
是一个编译时间常量,你可以根据bar
的值改变foo
的类型。例如:
#include <cstddef>
template<bool condition, std::size_t true_size, std::size_t false_size>
constexpr auto conditional(const char(&true_case)[true_size], const char(&false_case)[false_size]) -> typename std::enable_if<condition, const char(&)[true_size]>::type {
return true_case;
}
template<bool condition, std::size_t true_size, std::size_t false_size>
constexpr auto conditional(const char(&true_case)[true_size], const char(&false_case)[false_size]) -> typename std::enable_if<!condition, const char(&)[false_size]>::type {
return false_case;
}
// Or with C++17 constexpr if
template<bool condition, std::size_t true_size, std::size_t false_size>
constexpr auto conditional(const char(&true_case)[true_size], const char(&false_case)[false_size]) -> const char(&)[condition ? true_size : false_size] {
if constexpr (condition) {
return true_case;
} else {
return false_case;
}
}
// Usage:
auto foo = conditional<bar>("dolor", "sit");
只要两个字符串字面量大小相同,三元运算符的结果就是引用其中一个字符串字面量,并且这个结果是数组类型:
auto& x = true?"1234":"1234";
static_assert(is_same_v<decltype(x),const char (&)[5]>);
一旦三元运算符的结果成立,通常的语言规则适用:
无法复制 c 数组
const char y[5] = x; //error
c 数组的大小只能从初始化列表或当初始化为字符串文字时的 char 数组推导出来:
const char z[] = {'a','b'};
const char c[] = "abcd";
//no other way to deduce the size
我问 const char[]
而不是 const char*
。
我在用三元初始化时遇到了困难。鉴于 const bool bar
,我试过:
const char foo[] = bar ? "lorem" : "ipsum"
这给了我错误:
error: initializer fails to determine size of
foo
const char foo[] = bar ? { 'l', 'o', 'r', 'e', 'm', '[=15=]' } : { 'i', 'p', 's', 'u', 'm', '[=15=]' }
这给了我错误:
error: expected primary-expression before
{
token
有没有办法用三元初始化一个const char []
,或者我必须在这里切换到const char*
?
无法使用三元运算符初始化字符数组。这样做的原因是三元运算符的两边实际上都是用来构造一个对象的,而不是用来初始化对象的值的。由于您不能从一个数组初始化另一个数组,因此数组的三元初始化不起作用。
不过,如果您明确指定类型(并假设 C++17),它会用于 std::arrays
:
std::array k = b ? std::array{1, 2, 3, 4} : std::array{ 5, 6, 7 ,8};
请注意,数组的大小必须相同。在这种情况下根本无法使用不同大小的数组,因为三元运算符的两边必须是同一类型(并且数组的大小是其类型的一部分)。如果您的字符串大小不同,则必须使用 const char* const
.
由于字符串文字是左值,您可以对它们进行 const 引用,这可以在三元中使用。
// You need to manually specify the size
const char (&foo)[6] = bar ? "lorem" : "ipsum";
// Or (In C++11)
auto foo = bar ? "lorem" : "ipsum";
auto
的行为完全相同(除了您必须指定大小)。
如果你想对不同长度的字符串执行此操作,不幸的是“bool ? const char[x] : const char[y]
”只有在它们具有相同大小的情况下才会是数组类型(否则它们都会衰减为指针,并且表达式将是const char*
类型)。要解决此问题,您必须用 [=18=]
字符手动填充字符串(现在您不能执行 sizeof(foo) - 1
来获取大小,您必须执行 strlen(foo)
)。
例如,而不是:
auto foo = bar ? "abc" : "defg"; // foo is a const char*
你必须做的:
auto foo = bar ? "abc[=12=]" : "defg"; // foo is const char(&)[5]
// Note that if `bar` is true, foo is `{'a', 'b', 'c', '[=12=]', '[=12=]'}`
在您必须这样做之前,请考虑如果您将变量设置为 const char * const
,您的编译器很可能会将它们优化为与 const char[]
完全相同,并且如果您不更改值,如果它们只是 const char *
(末尾没有 const),也可能相同。
为了不意外地得到一个指针,并且如果你这样做很快就会失败,我会使用一个辅助函数:
#include <cstddef>
template<std::size_t size, std::size_t other_size = size>
constexpr auto conditional(bool condition, const char(&true_case)[size], const char(&false_case)[other_size]) noexcept -> const char(&)[size] {
static_assert(size == other_size, "Cannot have a c-string conditional with c-strings of different sizes");
return condition ? true_case : false_case;
}
// Usage:
auto foo = conditional(bar, "lorem", "ipsum");
如果bar
是一个编译时间常量,你可以根据bar
的值改变foo
的类型。例如:
#include <cstddef>
template<bool condition, std::size_t true_size, std::size_t false_size>
constexpr auto conditional(const char(&true_case)[true_size], const char(&false_case)[false_size]) -> typename std::enable_if<condition, const char(&)[true_size]>::type {
return true_case;
}
template<bool condition, std::size_t true_size, std::size_t false_size>
constexpr auto conditional(const char(&true_case)[true_size], const char(&false_case)[false_size]) -> typename std::enable_if<!condition, const char(&)[false_size]>::type {
return false_case;
}
// Or with C++17 constexpr if
template<bool condition, std::size_t true_size, std::size_t false_size>
constexpr auto conditional(const char(&true_case)[true_size], const char(&false_case)[false_size]) -> const char(&)[condition ? true_size : false_size] {
if constexpr (condition) {
return true_case;
} else {
return false_case;
}
}
// Usage:
auto foo = conditional<bar>("dolor", "sit");
只要两个字符串字面量大小相同,三元运算符的结果就是引用其中一个字符串字面量,并且这个结果是数组类型:
auto& x = true?"1234":"1234";
static_assert(is_same_v<decltype(x),const char (&)[5]>);
一旦三元运算符的结果成立,通常的语言规则适用:
无法复制 c 数组
const char y[5] = x; //error
c 数组的大小只能从初始化列表或当初始化为字符串文字时的 char 数组推导出来:
const char z[] = {'a','b'}; const char c[] = "abcd"; //no other way to deduce the size