数组初始化有一个很好的数组初始化列表。我有一个

int array[100] = {-1};

期望它充满-1,但它不是,只有第一个值是,其余都是0和随机值的混合。

的代码

int array[100] = {0};

工作很好,并将每个元素设置为0。

我错过了什么…如果值不为零,就不能初始化它吗?

和2:是默认的初始化(如上所述)比通常的循环通过整个数组和赋值还是做同样的事情?


当前回答

对于单字节元素数组,可以使用memset将所有元素设置为相同的值。

这里有一个例子。

其他回答

另一种将数组初始化为公共值的方法是实际生成一系列定义中的元素列表:

#define DUP1( X ) ( X )
#define DUP2( X ) DUP1( X ), ( X )
#define DUP3( X ) DUP2( X ), ( X )
#define DUP4( X ) DUP3( X ), ( X )
#define DUP5( X ) DUP4( X ), ( X )
.
.
#define DUP100( X ) DUP99( X ), ( X )

#define DUPx( X, N ) DUP##N( X )
#define DUP( X, N ) DUPx( X, N )

将数组初始化为一个公共值很容易做到:

#define LIST_MAX 6
static unsigned char List[ LIST_MAX ]= { DUP( 123, LIST_MAX ) };

注意:引入DUPx是为了在参数中对DUP进行宏替换

最简单的方法是使用std::array并编写一个函数模板,该函数模板将返回所需的std::array,其中所有元素都用传递的参数初始化,如下所示。

c++ 11版本

template<std::size_t N> std::array<int, N> make_array(int val)
{
    std::array<int, N> tempArray{};
    for(int &elem:tempArray)
    {
        elem = val;
    }
    return tempArray;
}
int main()
{
    //---------------------V-------->number of elements  
    auto arr  = make_array<8>(5);
    //------------------------^---->value of element to be initialized with

    
    //lets confirm if all objects have the expected value 
    for(const auto &elem: arr)
    {
        std::cout << elem << std::endl; //prints all 5 
    }
    
}

演示工作


c++ 17版本

在c++ 17中,你可以将constexpr添加到函数模板中,这样它就可以在constexpr上下文中使用:

//-----------------------------------------vvvvvvvvv--->added constexpr
template<std::size_t N> std::array<int, N> constexpr make_array(int val)
{
    std::array<int, N> tempArray{};
    for(int &elem:tempArray)
    {
        elem = val;
    }
    return tempArray;
}
int main()
{
//--vvvvvvvvv------------------------------>constexpr added
    constexpr auto arr  = make_array<8>(5);

    for(const auto &elem: arr)
    {
        std::cout << elem << std::endl;
    }
    
}

演示工作

用你用过的语法,

int array[100] = {-1};

表示“将第一个元素设置为-1,其余为0”,因为所有省略的元素都设置为0。

在c++中,要将它们都设置为-1,你可以使用类似std::fill_n (from <algorithm>):

std::fill_n(array, 100, -1);

在便携式C语言中,你必须自己进行循环。有编译器扩展,或者如果可以接受,可以依赖实现定义的行为作为快捷方式。

使用std::array,我们可以在c++ 14中以相当直接的方式做到这一点。这只能在c++ 11中实现,但是稍微复杂一些。

我们的接口是一个编译时大小和默认值。

template<typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, 0>, T &&) {
    return std::array<std::decay_t<T>, 0>{};
}

template<std::size_t size, typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, size>, T && value) {
    return detail::make_array_n_impl<size>(std::forward<T>(value), std::make_index_sequence<size - 1>{});
}


template<std::size_t size, typename T>
constexpr auto make_array_n(T && value) {
    return make_array_n(std::integral_constant<std::size_t, size>{}, std::forward<T>(value));
}

第三个函数主要是为了方便,所以用户不必自己构造std::integral_constant<std::size_t, size>,因为那是一个相当冗长的构造。真正的工作是由前两个函数中的一个完成的。

第一个重载非常简单:它构造了一个大小为0的std::数组。没有复制的必要,我们只是构造它。

第二个过载有点棘手。它沿着它得到的值作为源进行转发,它还构造了make_index_sequence的一个实例,并调用其他一些实现函数。这个函数是什么样的呢?

namespace detail {

template<std::size_t size, typename T, std::size_t... indexes>
constexpr auto make_array_n_impl(T && value, std::index_sequence<indexes...>) {
    // Use the comma operator to expand the variadic pack
    // Move the last element in if possible. Order of evaluation is well-defined
    // for aggregate initialization, so there is no risk of copy-after-move
    return std::array<std::decay_t<T>, size>{ (static_cast<void>(indexes), value)..., std::forward<T>(value) };
}

}   // namespace detail

This constructs the first size - 1 arguments by copying the value we passed in. Here, we use our variadic parameter pack indexes just as something to expand. There are size - 1 entries in that pack (as we specified in the construction of make_index_sequence), and they have values of 0, 1, 2, 3, ..., size - 2. However, we do not care about the values (so we cast it to void, to silence any compiler warnings). Parameter pack expansion expands out our code to something like this (assuming size == 4):

return std::array<std::decay_t<T>, 4>{ (static_cast<void>(0), value), (static_cast<void>(1), value), (static_cast<void>(2), value), std::forward<T>(value) };

我们使用这些括号来确保可变的包扩展…展开我们想要的内容,并确保我们使用了逗号操作符。如果没有括号,看起来就像我们在给数组初始化传递一堆参数,但实际上,我们是在计算索引,将它强制转换为void,忽略void结果,然后返回value,它被复制到数组中。

最后一个参数,我们称之为std::forward on,是一个小优化。如果有人传入一个临时的std::string并说“创建一个5个这样的数组”,我们希望有4个副本和1个移动,而不是5个副本。std::forward确保我们这样做。

完整的代码,包括头文件和一些单元测试:

#include <array>
#include <type_traits>
#include <utility>

namespace detail {

template<std::size_t size, typename T, std::size_t... indexes>
constexpr auto make_array_n_impl(T && value, std::index_sequence<indexes...>) {
    // Use the comma operator to expand the variadic pack
    // Move the last element in if possible. Order of evaluation is well-defined
    // for aggregate initialization, so there is no risk of copy-after-move
    return std::array<std::decay_t<T>, size>{ (static_cast<void>(indexes), value)..., std::forward<T>(value) };
}

}   // namespace detail

template<typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, 0>, T &&) {
    return std::array<std::decay_t<T>, 0>{};
}

template<std::size_t size, typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, size>, T && value) {
    return detail::make_array_n_impl<size>(std::forward<T>(value), std::make_index_sequence<size - 1>{});
}

template<std::size_t size, typename T>
constexpr auto make_array_n(T && value) {
    return make_array_n(std::integral_constant<std::size_t, size>{}, std::forward<T>(value));
}



struct non_copyable {
    constexpr non_copyable() = default;
    constexpr non_copyable(non_copyable const &) = delete;
    constexpr non_copyable(non_copyable &&) = default;
};

int main() {
    constexpr auto array_n = make_array_n<6>(5);
    static_assert(std::is_same<std::decay_t<decltype(array_n)>::value_type, int>::value, "Incorrect type from make_array_n.");
    static_assert(array_n.size() == 6, "Incorrect size from make_array_n.");
    static_assert(array_n[3] == 5, "Incorrect values from make_array_n.");

    constexpr auto array_non_copyable = make_array_n<1>(non_copyable{});
    static_assert(array_non_copyable.size() == 1, "Incorrect array size of 1 for move-only types.");

    constexpr auto array_empty = make_array_n<0>(2);
    static_assert(array_empty.empty(), "Incorrect array size for empty array.");

    constexpr auto array_non_copyable_empty = make_array_n<0>(non_copyable{});
    static_assert(array_non_copyable_empty.empty(), "Incorrect array size for empty array of move-only.");
}

c++ 11还有另一个(不完善的)选项:

std::array<int, 100> a;
a.fill(-1);