简体   繁体   English

如何根据元素数量终止可变参数模板递归?

[英]How do I terminate variadic template recursion based on the number of elements?

I've written a compile time search and find through template parameters, and it's working fine. 我已经编写了一个编译时搜索并通过模板参数查找,并且工作正常。 I'm stumped about how to go about providing a default value for when there is no item found. 我为找不到物品时如何提供默认值而感到困惑。

I've tried using sizeof...(args_t) to create a template specialization to terminate on. 我尝试使用sizeof ...(args_t)创建模板特化终止。 That isn't allowed. 那是不允许的。 And so, I'm not sure how to go about doing this. 因此,我不确定如何执行此操作。

Here's what I've got right now: 这是我现在得到的:

template <typename... args_t> class c
{
    template <size_t pos, typename _t, typename... a_t> struct at : at<pos - 1, a_t...> { };
    template <typename _t, typename... a_t> struct at<0, _t, a_t...>
    {
        using t = _t;
    };
};

What I need is something like: 我需要的是这样的:

template <typename... args_t> class c
{
    template <> struct at<sizeof...(args_t)>
    {
        using t = default_value;
    };
};

So, how do I go about creating a template specialization based on the number of variadic elements? 那么,如何基于可变参数的数量创建模板专业化?

You may use the following to manage case where index is outside bound: 您可以使用以下方法来管理索引超出范围的情况:

template <typename... args_t> class c
{
    template <std::size_t pos, typename... Ts> struct at;

    template <std::size_t pos, typename T, typename... Ts>
    struct at<pos, T, Ts...> : at<pos - 1, Ts...>
    {};

    template <typename T, typename... Ts>
    struct at<0, T, Ts...>
    {
        using type = T;
    };

    template <std::size_t N>
    struct at<N>
    {
        using type = void; // default type
    };

};

Live example 现场例子

Or using std::tuple and std::conditional (with lazy evaluation): 或使用std::tuplestd::conditional (带有惰性评估):

template <typename... args_t> class c
{
public:
    struct default_type { using type = void; };

    template <std::size_t pos, typename... Ts>
    struct at
    {
        using type =
            typename std::conditional<
                (pos < sizeof...(Ts)),
                std::tuple_element<pos, std::tuple<Ts...>>, // don't use ::type here
                default_type
            >::type::type; // expand type 'twice'.
    };

};

Live example 现场例子

This might not be the best way, but here goes. 这可能不是最好的方法,但是可以使用。 The premise is to implement it with being told explicitly whether or not to use the default type, and then having the exposed interface provide that template argument based on the conditions you want. 前提是通过明确告知是否使用默认类型来实现它,然后让暴露的接口根据所需条件提供该模板参数。

struct Default {}; //our default type

//basic template to specialize
template<std::size_t Pos, bool UseDefault, typename... Ts>
struct At_;

//handle the default; UseDefault will be true if Pos is out of range
template<std::size_t Pos, typename... Ts>
struct At_<Pos, true, Ts...> {
    using type = Default;
};

//handle base case of reaching the element at Pos;
template<typename Head, typename... Tail>
struct At_<0, false, Head, Tail...> {
    using type = Head;
};

//handle all other cases
template<std::size_t Pos, typename Head, typename... Tail>
struct At_<Pos, false, Head, Tail...> : At_<Pos - 1, false, Tail...> {};

//use the default if Pos is out of range
template<std::size_t Pos, typename... Ts>
using At = typename At_<Pos, sizeof...(Ts) <= Pos, Ts...>::type;

You can see it work with a few tests here . 您可以在这里通过一些测试看到它的工作。 This also seems to work for negative indices given a replacement for std::size_t that is signed. 如果替换了已签名的std::size_t ,这似乎也适用于负索引。 I would also recommend the At_ stuff go in a detail namespace of some sort. 我还建议将At_放在某种详细的名称空间中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM