简体   繁体   English

在编译时将std :: array转换为另一种数据类型?

[英]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 : 在编译时,C ++ 11中是否有一种方法可以将一种类型的数组转换为另一种数据类型:

#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;
}

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[] ): 不,但你可以使用索引技巧相当容易地手工完成,假设实现提供了constexpr std::get (或者等同于operator[]constexpr重载):

#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 ; 如果你的实现没有提供constexpr getoperator[] ,你就不能使用array因为没有当前的标准方法来访问数组元素constexpr ; your best bet is to use your own implementation of array with the constexpr extensions. 你最好的选择是使用你自己的constexpr扩展array实现。

The constexpr library additions are proposed for addition to the standard in n3470 . 建议将constexpr库添加到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: 而不是目前甚至无法使用最常用的C ++编译器编译的神秘模板代码,并且避免数字规范中的ungood冗余,只需使用宏:

#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;
}

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. 不幸的是,在这种情况下, iarray不再是constexpr

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM