【问题标题】:How do I terminate variadic template recursion based on the number of elements?如何根据元素数量终止可变参数模板递归?
【发布时间】:2014-09-19 19:27:51
【问题描述】:

我编写了一个编译时搜索并通过模板参数查找,它工作正常。当没有找到项目时,我对如何提供默认值感到困惑。

我尝试使用 sizeof...(args_t) 创建模板特化以终止。这是不允许的。所以,我不知道该怎么做。

这是我现在得到的:

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

我需要的是这样的:

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

那么,如何根据可变参数元素的数量创建模板特化?

【问题讨论】:

  • 你不能把它们打包成一个元组吗? using t = typename std::tuple_element&lt;pos, std::tuple&lt;Args...&gt;&gt;::type;
  • Little OT:以_t 结尾的名称在POSIX 系统中是保留的。
  • @chris 对这里有帮助吗?
  • @black,这适用于所有内容,还是仅适用于全局名称?
  • @MGaz,哦,我明白了。抱歉,我看错了问题。

标签: c++ templates c++11 variadic-templates template-specialization


【解决方案1】:

您可以使用以下方法来管理索引超出范围的情况:

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

或使用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

【讨论】:

  • 啊,聪明。我花了一点时间才弄清楚它在做什么,但是,是的,绝对比我的好。
【解决方案2】:

这可能不是最好的方法,但可以。前提是通过明确告知是否使用默认类型来实现它,然后让暴露的接口根据您想要的条件提供该模板参数。

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;

您可以通过一些测试 here 看到它的工作原理。考虑到已签名的std::size_t 的替代品,这似乎也适用于负指数。我还建议将At_ 的东西放在某种详细的命名空间中。

【讨论】:

    猜你喜欢
    • 2017-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-17
    • 1970-01-01
    相关资源
    最近更新 更多