【问题标题】:How to use the current class template as template parameter for another template?如何使用当前类模板作为另一个模板的模板参数?
【发布时间】:2017-10-26 21:05:07
【问题描述】:

我正在使用递归继承的递归模板类。
我正在尝试定义一种获取第 n 个基数的抽象方法(例如基数 0 是当前类,基数 1 是它的基数,基数 2 是基数的基数等)。

(在本例中,模板参数为size_t,但同样的原则也适用于typenameclass。)

我可以使用部分专用的辅助结构来做到这一点。但我想让它独立于模板(并且在我有递归模板时不制作辅助结构),如下所示:

namespace helper
{
    template<template<size_t...> typename templ, size_t pos, size_t s0, size_t... rest>
    struct getter
    {
        typedef typename getter<templ, pos - 1, rest...>::type type;
        type &operator()(templ<s0, rest...> &s)
        {
            getter<templ, pos - 1, rest...> getter;
            return getter(static_cast<templ<rest...>&> (s));
        }
    };
    template<template<size_t...> typename templ, size_t s0, size_t... rest>
    struct getter<templ, 0, s0, rest...>
    {
        typedef templ<s0, rest...> type;
        type &operator()(templ<s0, rest...> &s)
        {
            return s;
        }
    };
}

现在,在我的模板类中,我想使用这个助手来创建一个函数 get&lt;size_t n&gt;(),它返回一个对第 n 个基数的引用(代码在 get 声明处编译失败):

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

template<size_t n, size_t... rest>
struct record<n, rest...> : record<rest...>, value<n>
{
    template<size_t pos>
    typename helper::getter<record, pos, n, rest...>::type::value_type &get()
    {
        helper::getter<record, pos, n, rest...> getter;
        return static_cast<typename helper::getter<record, pos, n, rest...>::type::value_type&>(getter(*this));
    }
};

这失败了,因为在record 模板中,record 是最终类而不是模板。我想使用“当前模板”之类的东西,而不是“当前实例化的类”。

我发现的唯一解决方法(在 Visual Studio 2015 下有效)是使用全局别名来复制模板:

template<size_t...s>
using g_record = record<s...>;

然后修改get声明调用全局别名(指向同一类型):

...
template<size_t pos>
typename helper::getter<g_record, pos, n, rest...>::type::value_type &get()
{
    helper::getter<g_record, pos, n, rest...> getter;
    return static_cast<typename helper::getter<g_record, pos, n, rest...>::type::value_type&>(getter(*this));
}
...

有没有更直接或更“正确”的方法来做到这一点?

【问题讨论】:

    标签: c++ templates recursion metaprogramming


    【解决方案1】:

    看来我挖的有点仓促了。

    显然使用模板的完全限定名称有效(在我的示例中为::record):

        template<size_t pos>
        typename helper::getter<::record, pos, n, rest...>::type::value_type &get()
        {
            helper::getter<::record, pos, n, rest...> getter;
            return static_cast<typename helper::getter<::record, pos, n, rest...>::type::value_type&>(getter(*this));
        }
    

    【讨论】:

      【解决方案2】:

      不必使用任何技巧来让编译器意识到您正在使用record 作为模板名称,而不是引用当前实例化的类型名称。见 [temp.local]/1,强调我的:

      与普通(非模板)类一样,类模板有一个injected-class-name(第 9 条)。 injected-class-name 可以用作 template-nametype-name。当它与 template-argument-list 一起使用时, 作为模板模板参数模板参数,或作为详细类型说明符中的最终标识符 em> 的朋友类模板声明,它指的是类模板本身。否则,它相当于 template-name 后跟 &lt;&gt; 中包含的类模板的 template-parameters

      您发布的解决方法是正确的,但应该不需要;这是编译器中的一个错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-28
        • 1970-01-01
        • 1970-01-01
        • 2018-10-25
        • 1970-01-01
        • 2014-04-16
        • 1970-01-01
        相关资源
        最近更新 更多