Reputation: 60371
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;
}
Upvotes: 7
Views: 4855
Reputation: 60371
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;
}
Upvotes: 3
Reputation: 145269
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.
Upvotes: 2
Reputation: 157344
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.
Upvotes: 9
Reputation: 545588
You cannot cast, but you can copy:
static constexpr std::array<double, 3> darray{{1.5, 2.5, 3.5}};
std::array<int, 3> iarray;
std::copy(begin(darray), end(darray), begin(iarray));
Unfortunately iarray
cannot be constexpr
any more in this case.
Upvotes: 1