10

私はいくつかのテンプレートメタプログラミングを行おうとしていますが、あるタイプのある構造の特殊化の最高のインデックスを「抽出」する必要があることに気づいています。

たとえば、いくつかのタイプがある場合:

struct A
{
    template<unsigned int> struct D;
    template<> struct D<0> { };
};

struct B
{
    template<unsigned int> struct D;
    template<> struct D<0> { };
    template<> struct D<1> { };
};

struct C
{
    template<unsigned int> struct D;
    template<> struct D<0> { };
    template<> struct D<1> { };
    template<> struct D<2> { };
};

次に、次のようなメタ関数を作成するにはどうすればよいですか。

template<class T>
struct highest_index
{
    typedef ??? type;
    // could also be:   static size_t const index = ???;
};

構造体がカウントを明示的に宣言する必要なしDに、上記のような任意の構造体の内部に特化された最高のインデックスを私に与えるには?

4

3 に答える 3

4

これは、特殊化が定義されている最大のインデックスを取得する最初のバージョンです。これから、対応するタイプを取得します!

実装:

template<class T>
struct highest_index
{
  private:
     template<int i>
     struct is_defined {};

     template<int i>
     static char f(is_defined<sizeof(typename T::template D<i>)> *);

     template<int i>
     static int f(...);

     template<int i>
     struct get_index;

     template<bool b, int j>
     struct next
     {
        static const int value = get_index<j>::value;
     };
     template<int j>
     struct next<false, j>
     {
        static const int value = j-2;
     };
     template<int i>
     struct get_index
     {
        static const bool exists = sizeof(f<i>(0)) == sizeof(char);
        static const int value = next<exists, i+1>::value;
     };

    public:
     static const int index = get_index<0>::value; 
};

テストコード:

#include <iostream>

struct A
{
    template<unsigned int> struct D;
};
template<> struct A::D<0> { };
template<> struct A::D<1> { };

struct B
{
    template<unsigned int> struct D;
};
template<> struct B::D<0> { };
template<> struct B::D<1> { };
template<> struct B::D<2> { };


int main()
{
    std::cout << highest_index<A>::index << std::endl;
    std::cout << highest_index<B>::index << std::endl;
}

出力:

1
2

ライブデモ。:-)

于 2013-01-08T09:31:03.490 に答える
2

質問の下のコメントの助けを借りてそれを理解しました!

struct A { template<unsigned int> struct D; };
template<> struct A::D<0> { };

struct B { template<unsigned int> struct D; };
template<> struct B::D<0> { };
template<> struct B::D<1> { };

struct C { template<unsigned int> struct D; };
template<> struct C::D<0> { };
template<> struct C::D<1> { };
template<> struct C::D<2> { };
template<> struct C::D<3> { };

template<unsigned int>
static unsigned char test(...);

template<unsigned int N, class T>
static typename enable_if<
    sizeof(typename T::template D<N>),
    unsigned char (&)[1 + sizeof(test<N + 1>(T()))]
>::type test(T, typename T::template D<N> = typename T::template D<N>());

int main()
{
    return sizeof(test<0>(C())) - 1;  // Evaluates to number of specializations
}
于 2013-01-08T09:37:41.933 に答える
1

これが私の小さな貢献です。

まず、存在メソッドから始めます。

template <unsigned>
static unsigned char exists_impl(...);

template <unsigned N, typename T>
static auto exists_impl(T const&&) ->
    typename std::enable_if<sizeof(typename T::template D<N>),
                            unsigned char (&)[2]>::type;

template <typename T, unsigned N>
static constexpr bool exists() {
    return sizeof(exists_impl<N>(std::declval<T>())) != 1;
}

ここでは、関数の使用法が読みやすさの点でテーブルに多くをもたらすと信じているconstexprので、私は典型的なタイプを使用しません。

次に、読みやすさを損なう典型的な二分探索(2回目の試行、下部の最初の試行を参照)を使用しますが、遅延インスタンス化の恩恵を受けるために、部分的なテンプレートの特殊化を使用しますstd::conditional

template <typename T, unsigned low, unsigned high, typename = void>
struct highest_index_in;

template <typename T, unsigned low>
struct highest_index_in<T, low, low>: std::integral_constant<unsigned, low> {};

template <typename T, unsigned low, unsigned high>
struct highest_index_in<T, low, high, typename std::enable_if<(high == low + 1)>::type>:
  std::integral_constant<unsigned, low + exists<T, low+1>()> {};

template <typename T, unsigned low, unsigned high>
struct highest_index_in<T, low, high, typename std::enable_if<(high > low + 1)>::type>:
  std::conditional< exists<T, (low+high)/2>(),
                    highest_index_in<T, (low+high)/2, high>,
                    highest_index_in<T, low, (low+high)/2> >::type
{};

template <typename T>
static constexpr unsigned highest_index() {
   return highest_index_in<T, 0, ~(0u)>::value;
} // highest_index

ライブワークスペースでのデモ、コンピューティングhighest_index<C>()はほぼ瞬時に行われます。


バイナリ検索の最初の試みですが、残念ながら、コンパイラは関数本体を再帰的にインスタンス化する必要があり(インスタンス化できることを証明するため)、したがって、実行する必要のある作業は膨大です。

template <typename T, unsigned low, unsigned high>
static constexpr auto highest_index_in() ->
   typename std::enable_if<high >= low, unsigned>::type
{
   return low == high                 ? low :
          high == low + 1             ? (exists<T, high>() ? high : low) :
          exists<T, (high + low)/2>() ? highest_index_in<T, (high+low)/2, high>() :
                                        highest_index_in<T, low, (high+low)/2>();
} // highest_index_in

template <typename T>
static constexpr unsigned highest_index() {
   return highest_index_in<T, 0, ~(0u)>();
} // highest_index

そのため、残念ながら、highest_index使用できず、clangの動作が遅くなります(gccのパフォーマンスが向上しているようには見えません)。

于 2013-01-08T11:07:39.657 に答える