Cast an std::array to another data type at compile time? Cast an std::array to another data type at compile time? arrays arrays

Cast an std::array to another data type at compile time?


No, but you can do it by hand fairly easily using the indices trick, assuming the implementation provides constexpr std::get (or equivalently a constexpr overload of operator[]):

#include <iostream>#include <array>#include <type_traits>// http://loungecpp.wikidot.com/tips-and-tricks%3aindicestemplate <std::size_t... Is>struct indices {};template <std::size_t N, std::size_t... Is>struct build_indices: build_indices<N-1, N-1, Is...> {};template <std::size_t... Is>struct build_indices<0, Is...>: indices<Is...> {};template<typename T, typename U, size_t i, size_t... Is>constexpr auto array_cast_helper(   const std::array<U, i> &a, indices<Is...>) -> std::array<T, i> {   return {{static_cast<T>(std::get<Is>(a))...}};}template<typename T, typename U, size_t i>constexpr auto array_cast(   const std::array<U, i> &a) -> std::array<T, i> {   // tag dispatch to helper with array indices   return array_cast_helper<T>(a, build_indices<i>());}int main() {   static constexpr std::array<double, 3> darray{{1.5, 2.5, 3.5}};   static constexpr std::array<int, 3> iarray = array_cast<int>(darray);}

If your implementation doesn't provide constexpr get or operator[], you can't use array as there's no current standard way to access array elements constexpr; your best bet is to use your own implementation of array with the constexpr extensions.

The constexpr library additions are proposed for addition to the standard in n3470.


Instead of an unmaintainable mess of cryptic template code that won't even currently compile with the most commonly used C++ compiler, and avoiding ungood redundancy in the number specs, simply use a macro:

#include <iostream>#include <array>#include <type_traits>#define MY_VALUES( T ) {T(1.5), T(2.5), T(3.5)}int main(){    static constexpr std::array<double, 3>   darray  = { MY_VALUES( double ) };    static constexpr std::array<int, 3>      iarray  = { MY_VALUES( int ) };    // Whatever...}

This is the kind of stuff macros are good at.

Just make sure to minimize the possibility of name collision by using an all uppercase macro name, and maybe some custom prefix.


General advice: don't be too clever, keep it simple.

Keep in mind, someone has to maintain it later.


I've found a very simple solution with a single variadic function:

#include <iostream>#include <array>#include <type_traits>template<typename Type, typename OtherType, std::size_t Size, typename... Types, class = typename std::enable_if<sizeof...(Types) != Size>::type>constexpr std::array<Type, Size> convert(const std::array<OtherType, Size> source, const Types... data);template<typename Type, typename OtherType, std::size_t Size, typename... Types, class = typename std::enable_if<sizeof...(Types) == Size>::type, class = void>constexpr std::array<Type, Size> convert(const std::array<OtherType, Size> source, const Types... data);template<typename Type, typename OtherType, std::size_t Size, typename... Types, class>constexpr std::array<Type, Size> convert(const std::array<OtherType, Size> source, const Types... data){    return convert<Type>(source, data..., static_cast<const Type>(source[sizeof...(data)]));}template<typename Type, typename OtherType, std::size_t Size, typename... Types, class, class>constexpr std::array<Type, Size> convert(const std::array<OtherType, Size> source, const Types... data){    return std::array<Type, Size>{{data...}};}int main(){   static constexpr std::array<double, 3> darray{{1., 2., 3.}};   static constexpr std::array<int, 3> iarray = convert<int>(darray);   std::cout<<(std::integral_constant<int, iarray[2]>())<<std::endl;   return 0;}