5
template <int I> struct int_ {};

template < typename ... Pack >
struct thingy
{
    void call()
    {
       f(???);
    }
 };

インスタンス化すると、次のようになります。

struct thingy<int,char,double>
{
    void call()
    {
        f(int, int_<1>(), char, int_<2>(), double, int_<3>());
    }
}

あなたはどう思いますか?どのように?

私が考えることができる唯一のことは、次のように N 個の異なるパラメーターを使用して、thingy のオーバーロードを設定することです。

template < typename T0 > struct thingy<T0> { ... };
template < typename T0, typename T1 > struct thingy<T0,T1> { ... };

etc...

それぞれに呼び出しの実装があります。

4

2 に答える 2

5

できますか

はい、もちろん。

どのように ?

いくつかのステップで。

  • 整数の範囲を作成できる必要があります
  • 2つのシーケンスをインターリーブできる必要があります

整数の範囲から始めましょう。

template <size_t...>
struct IntegralPack {};

template <size_t A, size_t... N>
IntegralPack<N..., A> push_back(IntegralPack<N...>);

template <size_t A, size_t... N>
IntegralPack<A, N...> push_front(IntegralPack<N...>);

template <size_t L, size_t H>
struct IntegralRangeImpl {
    typedef typename IntegralRangeImpl<L+1, H>::type Base;
    typedef decltype(push_front<L>((Base()))) type;
};

template <size_t X>
struct IntegralRangeImpl<X, X> {
    typedef IntegralPack<> type;
};

template <size_t L, size_t H>
struct IntegralRange {
     static_assert(L <= H, "Incorrect range");
     typedef typename IntegralRangeImpl<L, H>::type type;
};

変換手順は(ありがたいことに)非常に簡単です。

template <typename...>
struct TypePack {};

template <size_t... N>
TypePack<int_<N>...> to_int(IntegralPack<N...>);

したがって、次の難しさはマージです。

template <typename... As, typename... Bs>
TypePack<As..., Bs...> cat(TypePack<As...>, TypePack<Bs...>);

template <typename, typename> struct Interleaver;

template <>
struct Interleaver<TypePack<>, TypePack<>> {
  typedef TypePack<> type;
};

template <typename A0, typename B0, typename... As, typename... Bs>
struct Interleaver<TypePack<A0, As...>, TypePack<B0, Bs...>> {
  typedef typename Interleaver<TypePack<As...>, TypePack<Bs...>>::type Base;
  typedef decltype(cat(TypePack<A0, B0>{}, Base{})) type;
};

まとめると:

template <typename... Pack>
struct thingy {
    typedef typename IntegralRange<1, sizeof...(Pack) + 1>::type Indexes;
    typedef decltype(to_int(Indexes{})) Ints;
    typedef typename Interleaver<TypePack<Pack...>, Ints>::type Types;

    void call() { this->callImpl(Types{}); }

    template <typename... Ts>
    void callImpl(TypePack<Ts...>) {
        f(Ts{}...);
    }
};

タダム!

于 2012-05-10T07:46:09.390 に答える
0

ですから、私が行った方法は、私が実際に行っていたことにもう少し具体的です。ポイントの横にあると私が思ったいくつかの情報が私を助けてくれたことがわかりました。どんな場合でも同様のテクニックが使えると思います。

一つには...私の場合、「thingy <>」には実際に値が含まれており、呼び出し元の関数に渡されます。これは実際に大いに役立ちます。

また、目的は、thingyの内容を変換して、別の奇妙なthingyのインデュースとして機能させることであり、渡されるintは、最初のthingyのインデックスを作成することでした...再帰を実行すると、intはすべて1になります。したがって、私が求めていたのは次のようなものでしたが(2番目のタプルを削除するために簡略化):

f(get(my_thingy, idx<1>), get(my_thingy, idx<2>), ...)

再帰によってidx<2>...idxが削除されることがわかりました。

template < typename Fun, typename H, typename ... T, typename ... Args >
auto call(Fun f, thingy<H,T...> const& t, Args&& ... args) 
  -> decltype(call(f,static_cast<thingy<T...>const&>(t), get(t,idx<1>), std::forward<Args>(args)...)
{
    return call(f, static_cast<thingy<T...>const&>(t), get(t, idx<1>), args...);
}

template < typename Fun, typename ... Args >
auto call(Fun f, thingy<> const&, Args&& ... args)
   -> decltype(f(std::forward<Args>(args)...))
{
    return f(std::forward<Args>(args)...);
}

getconst&...を使用すると、何らかの理由で関数が失敗するため、完全にテストできませんでした。しかし、これでうまくいくと私はかなり確信しています。

idxへのパラメーターが常に1であるとは限らない場合、同様の方法で転送できると思います。

于 2012-05-11T23:43:35.433 に答える