2

std::tupleのようなタイプで構成されているとします

struct A {
  static void tip();
};

struct B {
  static void tip();
};

struct Z {
};

std::tuple<const A&,const B&,const Z&> tpl;

はい、別Aの ,が必要Bです。( の実装は::tip()型ごとに異なります。) 私が実装しようとしているのは、タプルを最初から最後まで繰り返し処理する型依存の「ビジター」です。タイプの特定の要素にアクセスすると、メソッドがあるTかどうかに応じて関数を呼び出す必要があります。上記の簡単な例では実装しているとは限りません。したがって、反復子は、メソッドを使用して型の関数を 2 回呼び出し、もう 1 つの関数を 1 回呼び出す必要があります。T::tip()AB::tip()Z::tip()

これが私が思いついたものです:

template< int N , bool end >
struct TupleIter
{
  template< typename T , typename... Ts >
  typename std::enable_if< std::is_function< typename T::tip >::value , void >::type
  static Iter( const T& dummy , const std::tuple<Ts...>& tpl ) {
    std::cout << "tip\n";
    std::get<N>(tpl); // do the work
    TupleIter<N+1,sizeof...(Ts) == N+1>::Iter( std::get<N+1>(tpl) , tpl );
  }

  template< typename T , typename... Ts >
  typename std::enable_if< ! std::is_function< typename T::tip >::value , void >::type
  static Iter( const T& dummy , const std::tuple<Ts...>& tpl ) {
    std::cout << "no tip\n";
    std::get<N>(tpl); // do the work
    TupleIter<N+1,sizeof...(Ts) == N+1>::Iter( std::get<N+1>(tpl) , tpl );
  }
};


template< int N >
struct TupleIter<N,true>
{
  template< typename T , typename... Ts >
  static void Iter( const std::tuple<Ts...>& tpl ) {
    std::cout << "end\n";
  }
};

dummyイテレータの位置で要素の型のインスタンスを使用し、enable_if呼び出す関数を決定します。残念ながら、これは機能しません/良い解決策ではありません:

  1. コンパイラは、再帰的なインスタンス化について不平を言っています
  2. これconst T& dummyはクリーンなソリューションではありません

enable_if決定を行うための正しい戦略であるかどうか、std::tupleおよび最初のタイプをキャプチャして残りのすべての引数を重要な状態に保つことを再帰的に反復するにはどうすればよいか疑問に思っていました。タプルを分割する方法をお読みください。しかし、それは決定を下しません。

C ++ 11で、そのようなものを正しく移植可能な方法で実装するにはどうすればよいですか?

4

2 に答える 2

4

うーん、思ったより難しかったですが、これはうまくいきました。

あなたが間違っていた/私が修正したいくつかのこと:

  1. std::is_function< typename T::tip >::valuethis: は型ではないため、評価できませんT::tipT::tipこれが評価できたとしても、存在しない場合はどうなるでしょうか。置換はまだ失敗します。
  2. タプルの内部型として const 参照を使用するため、その中のヒント メンバーを見つける前にそれらをきれいにする必要がありました。クリーニングとは、 const を削除して参照を削除することを意味します。
  3. そのダミー タイプのものは良い考えではありませんでした。そのパラメーターを使用する必要はありませんでした。std::tuple_elementタプルから i 番目の型を取得するを使用して、同じことを実現できます。
  4. TupleIterのテンプレート パラメータを次のように変更しました。つまり、次のようになります。

"TupleIterサイズ n のタプル内で index 番目の型を処理する".

template<size_t index, size_t n> 
struct TupleIter;

コード全体は次のとおりです。

#include <tuple>
#include <iostream>
#include <type_traits>

struct A {
  static void tip();
};

struct B {
  static void tip();
};

struct Z {
};

// Indicates whether the template parameter contains a static member named tip.
template<class T>
struct has_tip {
    template<class U>
    static char test(decltype(&U::tip));

    template<class U>
    static float test(...);

    static const bool value = sizeof(test<typename std::decay<T>::type>(0)) == sizeof(char);
};

// Indicates whether the n-th type contains a tip static member
template<size_t n, typename... Ts>
struct nth_type_has_tip {
    static const bool value = has_tip<typename std::tuple_element<n, std::tuple<Ts...>>::type>::value;
};

// Generic iteration
template<size_t index, size_t n>
struct TupleIter
{
  template< typename... Ts >
  typename std::enable_if< nth_type_has_tip<index, Ts...>::value , void >::type
  static Iter(const std::tuple<Ts...>& tpl) 
  {
    std::cout << "tip\n";
    TupleIter<index + 1, n>::Iter(tpl );
  }

  template< typename... Ts >
  typename std::enable_if< !nth_type_has_tip<index, Ts...>::value , void >::type
  static Iter(const std::tuple<Ts...>& tpl) {
    std::cout << "no tip\n";
    TupleIter<index + 1, n>::Iter(tpl );
  }
};

// Base class, we've reached the tuple end
template<size_t n>
struct TupleIter<n, n>
{
  template<typename... Ts >
  static void Iter( const std::tuple<Ts...>& tpl ) {
    std::cout << "end\n";
  }
};

// Helper function that forwards the first call to TupleIter<>::Iter
template<typename... Ts>
void iterate(const std::tuple<Ts...> &tup) {
    TupleIter<0, sizeof...(Ts)>::Iter(tup);
}

int main() {
    A a;
    B b;
    Z z;
    std::tuple<const A&,const B&,const Z&> tup(a,b,z);
    iterate(tup);
}
于 2012-08-07T12:12:09.793 に答える