如何检测可变参数模板中的第一个和最后一个参数?

时间:2011-10-05 12:57:25

标签: c++ arguments c++11 variadic-templates

如何检测可变参数模板中的第一个和最后一个参数?

对于第一个参数,它很容易(只需将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;
}

2 个答案:

答案 0 :(得分:25)

如果这是你想要的,我不是肯定的。但是这里有两个名为firstlast的实用程序,它们分别采用可变参数模板和typedef第一个和最后一个类型:

#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';
}

答案 1 :(得分:3)

这是另一组带有便捷函数return_type的代码,您可以使用它来访问varadic模板列表中特定索引的任何类型...然后您可以调用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的{​​{1}}模板参数为return_type,因此您将获得2类型作为输出。任何超过char的数字都会导致溢出,从而产生编译而不是运行时错误。如上所述,您可以对其进行调整,使其包含在结构中的函数内,该结构允许您使用应用于枚举的2访问该特定结构实例的可变参数模板中的类型。例如:

sizeof...(TypeList) - 1