7

C ++ 11で、コンパイル時に1つの型の配列を別のデータ型にキャストする方法はありますか?

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

4 に答える 4

9

いいえ。ただし、実装が(または同等にのオーバーロード)を提供すると仮定すると、インデックストリックを使用して手作業でかなり簡単に行うことができます。constexpr std::getconstexproperator[]

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

実装でまたはが提供されていない場合、constexpr get配列要素にアクセスするための現在の標準的な方法がoperator[]ないため、使用できません。最善の策は、拡張機能を使用して独自の実装を使用することです。arrayconstexprarrayconstexpr

constexprライブラリの追加は、 n3470の標準に追加するために提案されています。

于 2013-01-11T14:39:43.203 に答える
2

現在最も一般的に使用されているC++コンパイラでさえコンパイルされない不可解なテンプレートコードの維持不可能な混乱の代わりに、数値仕様の不適切な冗長性を回避するために、単にマクロを使用します。

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

これは、マクロが得意な種類のものです。

すべて大文字のマクロ名と、場合によってはカスタムプレフィックスを使用して、名前の衝突の可能性を最小限に抑えるようにしてください。


一般的なアドバイス:賢くなりすぎないで、シンプルにしてください。

覚えておいてください、誰かが後でそれを維持しなければなりません。

于 2013-01-11T14:57:36.080 に答える
2

単一の可変個引数関数を使用した非常に単純なソリューションを見つけました。

#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;
}
于 2013-01-11T20:32:04.593 に答える
1

キャストすることはできませんが、コピーすることはできます。

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));

残念ながら、この場合はこれ以上iarrayできません。constexpr

于 2013-01-11T14:11:57.990 に答える