我可以用三元数初始化char []吗?

时间:2018-12-11 16:41:15

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

我问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*

3 个答案:

答案 0 :(得分:2)

无法使用三元运算符初始化字符数组。这样做的原因是三元运算符的两面实际上都用于构造对象,然后将该对象用于初始化值。由于您无法从另一个数组初始化一个数组,因此数组的三元初始化不起作用。

如果您明确指定类型(并假设使用C ++ 17),那么std::arrays的情况将是这样:

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

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

答案 1 :(得分:1)

由于字符串文字是左值,因此可以采用它们的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*)。要解决此问题,您必须手动用\0个字符填充字符串(现在您无法执行sizeof(foo) - 1来获取大小,而必须执行strlen(foo))。 / p>

例如,代替:

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是编译时间常数,则可以根据foo的值来更改bar的类型。例如:

#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");

答案 2 :(得分:1)

只要两个字符串文字的大小相同,三元运算符的结果将引用两个字符串文字中的任何一个,并且此结果具有数组类型:

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

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

  • c数组无法复制

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

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