【问题标题】:Can I Initialize a char[] with a Ternary?我可以用三进制初始化 char[] 吗?
【发布时间】:2019-05-12 17:00:11
【问题描述】:

我问过a question about it 并没有得到真正明确的答案,但在阅读了this article 之后,我开始更喜欢const char[] 而不是const char*

我在使用三元进行初始化时遇到了困难。给定const bool bar,我试过了:

  1. const char foo[] = bar ? "lorem" : "ipsum" 这给了我错误:

错误:初始化程序无法确定 foo 的大小

  1. const char foo[] = bar ? { 'l', 'o', 'r', 'e', 'm', '\0' } : { 'i', 'p', 's', 'u', 'm', '\0' } 这给了我错误:

错误:{ 令牌之前的预期主表达式

有没有办法用三元初始化const char [],还是我必须在这里切换到const char*

【问题讨论】:

  • @SergeyA 呃,我想我只拼错了一次,对吧? (在标题 T.T)
  • bar 是编译时间常数吗?
  • @NathanOliver 我的意思是在我的情况下不是,但如果我们能得到 bar 是编译时间常数的情况的部分答案,我会接受。
  • 我虽然做了,但没用。这里的语言真的很严格。

标签: c++ arrays ternary char-pointer variable-initialization


【解决方案1】:

没有办法用三元运算符初始化字符数组。原因是三元运算符的两边实际上是用来构造一个对象,而不是对象是用来初始化值的。由于您无法从另一个数组初始化一个数组,因此数组的三元初始化不起作用。

不过,它适用于 std::arrays,前提是您明确指定类型(并假设 C++17):

std::array k = b ? std::array{1, 2, 3, 4} : std::array{ 5, 6, 7 ,8};

请注意,数组的大小必须相同。在这种情况下根本没有办法使用不同大小的数组,因为三元运算符的两边必须是相同的类型(并且数组的大小是它类型的一部分)。如果您的字符串大小不同,则必须使用const char* const

【讨论】:

  • @NathanOliver 当然是同类型的。这是三元运算符所必需的 - 左侧和右侧必须具有相同的大小。这确实是一个好点。
  • 不幸的是,我的案例涉及 2 个不同长度的文字 c 字符串。所以这在不同的情况下可能会有所帮助,但在我看来我只需要使用const char*。如果没有人给出更好的答案,我明天会接受。
【解决方案2】:

由于字符串字面量是左值,因此可以对它们进行 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]”只有在它们具有相同大小的情况下才会是一个数组类型(否则它们都会衰减为指针,并且表达式的类型为@987654324 @)。要解决这个问题,您必须手动用\0 字符填充字符串(现在您不能使用sizeof(foo) - 1 来获取大小,您必须使用strlen(foo))。

例如,而不是:

auto foo = bar ? "abc" : "defg";  // foo is a const char*

你必须这样做:

auto foo = bar ? "abc\0" : "defg"; // foo is const char(&)[5]
// Note that if `bar` is true, foo is `{'a', 'b', 'c', '\0', '\0'}`

在您必须这样做之前,请考虑如果您将变量设置为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");

【讨论】:

    【解决方案3】:

    只要两个字符串字面量大小相同,三元运算符的结果就引用其中一个字符串字面量,而且这个结果是数组类型:

    auto& x = true?"1234":"1234";
    static_assert(is_same_v<decltype(x),const char (&)[5]>);
    

    一旦三元运算符的结果成立,通常的语言规则就适用:

    • c-array 无法复制

      const char y[5] = x; //error
      
    • 当初始值设定项是字符串字面量时,只能从初始值设定项列表或 char 数组推导出 c 数组的大小:

      const char z[] = {'a','b'};
      const char c[] = "abcd";
      //no other way to deduce the size
      

    【讨论】:

      猜你喜欢
      • 2019-05-02
      • 2011-02-15
      • 2020-09-17
      • 2010-09-29
      • 2021-11-30
      • 1970-01-01
      • 2019-12-01
      • 2020-12-31
      • 1970-01-01
      相关资源
      最近更新 更多