0

カスタム ベクター オブジェクトを初期化しようとしていますが、std::initializer_list. 私はこのようなことをしています:

template <typename T, std::size_t N>
struct vector
{
  template<std::size_t I = 0, typename ...Tp>
  typename std::enable_if<I == sizeof...(Tp), void>::type
  unpack_tuple(std::tuple<Tp...> const& t)
  {
  }

  template<std::size_t I = 0, typename ...Tp>
  typename std::enable_if<I != sizeof...(Tp), void>::type
  unpack_tuple(std::tuple<Tp...> const& t)
  {
    store[I] = std::get<I>(t);

    unpack_tuple<I + 1, Tp...>(t);
  }

  template<typename ...U>
  vector(U&&... args,
    typename std::enable_if<std::is_scalar<U...>::value, void>::type* = 0)
  {
    unpack_tuple(std::forward_as_tuple(std::forward<U>(args)...));
  }

  T store[N];
};

ただし、必要な引数を削除しない限り、コンパイラはコンストラクターstd::enable_ifを認識しません (非スカラー引数は必要ないため)。解決策はありますか?

4

1 に答える 1

4

std::is_scalar<U...>::value

is_scalar問題は、単一の型引数のみを取るという事実にあります。複数のブール値を組み合わせたラッパーを作成する必要があります。また、とにかくスカラー型のみが必要な場合に、完全な転送を使用する理由も疑問に思います。値で渡すだけです。Uこのように、左辺値が渡されたときに参照として推測されることを心配する必要もありません。

#include <type_traits>

template<bool B>
using bool_ = std::integral_constant<bool, B>;

template<class Head, class... Tail>
struct all_of
  : bool_<Head::value && all_of<Tail...>::value>{};

template<class Head>
struct all_of<Head> : bool_<Head::value>{};

template<class C, class T = void>
using EnableIf = typename std::enable_if<C::value, T>::type;

// constructor
template<typename... U>
vector(U... args, EnableIf<all_of<std::is_scalar<U>...>>::type* = 0)
{
  unpack_tuple(std::tie(args...)); // tie makes a tuple of references
}

上記のコードは機能するはずです。ただし、アドバイスとして、何かが必要ないstatic_assert場合は、それを取得せず、そのためにSFINAEを悪用しないようにしてください。:) SFINAEは、オーバーロードされたコンテキストでのみ使用する必要があります。

// constructor
template<typename... U>
vector(U... args)
{
  static_assert(all_of<std::is_scalar<U>...>::value, "vector only accepts scalar types");
  unpack_tuple(std::tie(args...)); // tie makes a tuple of references
}

実際の質問についてはこれだけですが、インデックスのトリックを使用して、タプル(または一般的な可変個引数、あるいは配列)を解凍するためのより良い方法をお勧めします:

template<unsigned...> struct indices{};
template<unsigned N, unsigned... Is> struct indices_gen : indices_gen<N-1, N-1, Is...>{};
template<unsigned... Is> struct indices_gen<0, Is...> : indices<Is...>{};

template<unsigned... Is, class... U>
void unpack_args(indices<Is...>, U... args){
  [](...){}((store[Is] = args, 0)...);
}

template<class... U>
vector(U... args){
  static_assert(all_of<std::is_scalar<U>...>::value, "vector only accepts scalar types");
  unpack_args(indices_gen<sizeof...(U)>(), args...);
}

このコードが行うことは、可変個引数の解凍メカニズムを「悪用」することです。まず、インデックスのパックを生成し、[0 .. sizeof...(U)-1]次にこのリストを。と一緒にロックステップで展開しargsます。パック拡張は特定の場所でのみ発生する可能性があるため、この拡張を可変個引数(非テンプレート)関数の引数リスト内に配置します。これはその1つです。別の可能性は、ローカル配列としてです。

template<unsigned... Is, class... U>
void unpack_args(indices<Is...>, U... args){
  int a[] = {(store[Is] = args, 0)...};
  (void)a; // suppress unused variable warnings
}
于 2012-10-07T18:04:39.357 に答える