How to Emulate C Array Initialization "Int Arr[] = { E1, E2, E3, ... }" Behaviour With Std::Array

Array initialization with identical elements

Here's a compile time solution that uses initialisation (uses std::array instead of a C array):

template<std::size_t N, typename T, std::size_t... Is>
constexpr std::array<T, N> make_filled_array(
std::index_sequence<Is...>,
T const& value
)
{
return {((void)Is, value)...};
}

template<std::size_t N, typename T>
constexpr std::array<T, N> make_filled_array(T const& value)
{
return make_filled_array<N>(std::make_index_sequence<N>(), value);
}

auto xs = make_filled_array<300, int>(10);
auto ys = make_filled_array<300>(10);

In struct nested union/array member default initialization compiles, but is not happening correctly?

What you are doing is aggregate initialization, which means the elements in sArray and dArray are value initialized when not specified. Because short and double are scalar types, this means zero initialization

Since you don't specify anything but the first element, all remaining elements will be initialized to 0

As requested in the comments, a way to initialize the arrays would be std::fill or std::fill_n:

#include <algorithm>

struct Nested {
explicit Nested() {
std::fill_n(sArray, 5, 0);
std::fill_n(dArray, 5, 0.0);
}
union {
short sArray[5];
float fVal; // Must NOT be initialized - obviously, only 1 member of a
// union can be
};

double dArray[5];
};

In general, I would recommend to instead use std::array and its fill function:

#include <array>

struct Nested {
explicit Nested() {
sArray.fill(0);
dArray.fill(0.0);
}
union {
std::array<short, 5> sArray;
float fVal; // Must NOT be initialized - obviously, only 1 member of a
// union can be
};

std::array<double, 5> dArray;
};

Getting root type of multidimensional variadic std::array

You can use a basic recursive technique:

template <typename T>
struct nested_value_type { using type = T; };

template <typename T, std::size_t N>
struct nested_value_type<std::array<T, N>>
{
using type = typename nested_value_type<T>::type;
};

Provide an alias template for convenience:

template <typename T>
using nested_value_type_t = typename nested_value_type<T>::type;

And voila:

static_assert(std::is_same_v<
nested_value_type_t<std::array<int, 1>>,
int
>);

static_assert(std::is_same_v<
nested_value_type_t<std::array<std::array<float, 1>, 1>>,
float
>);

static_assert(std::is_same_v<
nested_value_type_t<std::array<std::array<std::array<char, 1>, 1>, 1>>,
char
>);

live example on godbolt.org


A bit shorter with C++20's std::type_identity:

template <typename T>
struct nested_value_type : std::type_identity<T> { };

template <typename T>
using nested_value_type_t = typename nested_value_type<T>::type;

template <typename T, std::size_t N>
struct nested_value_type<std::array<T, N>>
: std::type_identity<nested_value_type_t<T>> { };

Narrowing conversions in C++0x. Is it just me, or does this sound like a breaking change?

I ran into this breaking change when I used GCC. The compiler printed an error for code like this:

void foo(const unsigned long long &i)
{
unsigned int a[2] = {i & 0xFFFFFFFF, i >> 32};
}

In function void foo(const long long unsigned int&):

error: narrowing conversion of (((long long unsigned int)i) & 4294967295ull) from long long unsigned int to unsigned int inside { }

error: narrowing conversion of (((long long unsigned int)i) >> 32) from long long unsigned int to unsigned int inside { }

Fortunately, the error messages were straightforward and the fix was simple:

void foo(const unsigned long long &i)
{
unsigned int a[2] = {static_cast<unsigned int>(i & 0xFFFFFFFF),
static_cast<unsigned int>(i >> 32)};
}

The code was in an external library, with only two occurrences in one file. I don't think the breaking change will affect much code. Novices might get confused, though.



Related Topics



Leave a reply



Submit