17

可変個引数テンプレートの最初と最後の引数を検出するにはどうすればよいですか?

最初の引数については簡単です(sizeof...(T)0と比較するだけです)が、最後の要素を検出する方法はありますか?

例 :

#include <iostream>
#include <typeinfo>

template < class... T >
struct A
{
    int foo(int k){ return k; };
};

template < class T1, class... T >
struct A< T1, T... >
{
    A() :a()
    {
        std::cout<<"A  i="<<sizeof...(T)<<std::endl
                 <<"   a type = " << typeid(T1).name()<<std::endl;
    }

    int foo(int k){ return anotherA.foo( a.foo(k) ); };

    T1 a;
    A< T... > anotherA;
};

struct B1
{
    B1(){ std::cout<<"b1"<<std::endl; };
    int foo(int k){ std::cout<<"b1::foo() k="<<k<<std::endl; return k+1; };
};
struct B2
{
    B2(){ std::cout<<"b2"<<std::endl; };
    int foo(int k){ std::cout<<"b2::foo() k="<<k<<std::endl; return k+2; };
};
struct B3
{
    B3(){ std::cout<<"b3"<<std::endl; };
    int foo(int k){ std::cout<<"b3::foo() k="<<k<<std::endl; return k+3; };
};

int main ()
{
    A< B3, B2, B1 > a;

    std::cout<<"the value is "
             <<a.foo(5)
             << std::endl;
}
4

2 に答える 2

26

これがあなたの望むものかどうか、私は確信が持てません。しかし、可変個引数テンプレートと typedef をそれぞれ最初と最後の型にする とfirstという名前の 2 つのユーティリティがあります。last

#include <iostream>
#include <typeinfo>

template <class T1, class ...T>
struct first
{
    typedef T1 type;
};

template <class T1, class ...T>
struct last
{
    typedef typename last<T...>::type type;
};

template <class T1>
struct last<T1>
{
    typedef T1 type;
};

template <class ...T>
struct A
{
    typedef typename first<T...>::type first;
    typedef typename last<T...>::type  last;
};

struct B1 {};
struct B2 {};
struct B3 {};

int main()
{
    typedef A<B1, B2, B3> T;
    std::cout << typeid(T::first).name() << '\n';
    std::cout << typeid(T::last).name() << '\n';
}
于 2011-10-05T16:08:17.403 に答える
3

これは、varadicテンプレートリストの特定のインデックスにある任意の型にアクセスするために使用できる便利な関数を備えた別のコードセットreturn_typeです...次に、最初と最後の引数を取得するように呼び出しを適応させることができreturn_typeます(つまり、最初の引数は0になり、最後の引数はsizeof...(TypeList))になります。

template<typename T>
struct type_id_struct
{
    typedef T type;
    T object_instance;
};

template<int N, typename... TypeList>
struct reduce {};

template<int N, typename T1, typename... TypeList>
struct reduce<N, T1, TypeList...>
{
    typedef typename reduce<N - 1, TypeList... >::type type;
};

template<typename T1, typename... TypeList>
struct reduce<0, T1, TypeList...>
{
    typedef T1 type;
};

//convenience function
template<int N, typename... TypeList>
type_id_struct<typename reduce<N, TypeList...>::type> return_type()
{
        return type_id_struct<typename reduce<N, TypeList...>::type>();
}

return_type実際のコードで便利関数を使用して、可変個引数テンプレートのN番目のテンプレート引数を決定する例を次に示します。

int main()
{
    auto type_returned = return_type<2, int, double, char>();
    std::cout << typeid(type_returned.object_instance).name() << std::endl;

    return 0;
}

この場合、のintテンプレート引数return_type2であるため、出力として型を取得しcharます。数値を超える2とオーバーフローが発生し、実行時エラーではなくコンパイルエラーが発生します。前述のようにsizeof...(TypeList) - 1、列挙型に適用されたものを使用して、その特定の構造体インスタンスの可変個引数テンプレートの型にアクセスできるようにする構造体の関数内にラップされるように調整できます。例えば:

template<typename... TypeList>
struct an_object
{
    enum { first = 0, last = (sizeof...(TypeList) - 1) };

    template<int N>
    auto wrapper() -> decltype(return_type<N, TypeList...>())
    {
            return return_type<N, TypeList...>();
    }
};

//...more code

int main()
{
    an_object<int, double, char> a;

    auto r_type1 = a.wrapper<an_object<int, double, char>::first>();
    std::cout << typeid(r_type1.object_instance).name() << std::endl;

    auto r_type2 = a.wrapper<an_object<int, double, char>::last>();
    std::cout << typeid(r_type2.object_instance).name() << std::endl;

    return 0;
}
于 2011-10-05T18:01:36.267 に答える