Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Is there a way in C++11 to cast an array of one type to another data type at compile-time :

#include <iostream>
#include <array>
#include <type_traits>

int main()
{
   static constexpr std::array<double, 3> darray{{1.5, 2.5, 3.5}};
   static constexpr std::array<int, 3> iarray(darray); // not working
   // Is there a way to cast an array to another data type ? 
   return 0;
}
like image 485
Vincent Avatar asked Jan 11 '13 14:01

Vincent


2 Answers

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%3aindices
template <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.

like image 58
ecatmur Avatar answered Sep 27 '22 18:09

ecatmur


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.

like image 23
Cheers and hth. - Alf Avatar answered Sep 27 '22 18:09

Cheers and hth. - Alf