如何使用当前class模板作为另一个模板的模板参数?
How to use the current class template as template parameter for another template?
我正在使用递归模板 classes 递归继承。
我正在尝试定义一种获取第 n 个基数的抽象方法(例如基数 0 是当前 class,基数 1 是它的基数,基数 2 是基数的基数等)。
(在此示例中,模板参数为 size_t
,但同样的原则适用于 typename
或 class
。)
我可以使用部分专门化的辅助结构来完成这项工作。但是我想让它独立于模板(而不是在我有递归模板的时候做一个辅助结构),如下:
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;
}
};
}
现在,在我的模板 class 中,我想使用这个助手来创建一个函数 get<size_t n>()
,returns 我是第 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
是最终的 class 而不是模板。我想使用 "current template" 而不是 "currently instantiated class"。
我发现的唯一解决方法(在 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));
}
...
是否有更直接或 "correct" 的方式来做到这一点?
看来我的挖掘有点仓促。
显然可以使用模板的完全限定名称(在我的示例中是 ::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));
}
不必使用任何技巧让编译器意识到您正在使用 record
作为模板名称而不是引用当前实例化的类型名称。见 [temp.local]/1,强调我的:
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list,
as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type-specifier of a friend class template declaration, it refers to the class template itself. Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>
.
您发布的解决方法是正确的,但应该不需要;这是编译器中的错误。
我正在使用递归模板 classes 递归继承。
我正在尝试定义一种获取第 n 个基数的抽象方法(例如基数 0 是当前 class,基数 1 是它的基数,基数 2 是基数的基数等)。
(在此示例中,模板参数为 size_t
,但同样的原则适用于 typename
或 class
。)
我可以使用部分专门化的辅助结构来完成这项工作。但是我想让它独立于模板(而不是在我有递归模板的时候做一个辅助结构),如下:
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;
}
};
}
现在,在我的模板 class 中,我想使用这个助手来创建一个函数 get<size_t n>()
,returns 我是第 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
是最终的 class 而不是模板。我想使用 "current template" 而不是 "currently instantiated class"。
我发现的唯一解决方法(在 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));
}
...
是否有更直接或 "correct" 的方式来做到这一点?
看来我的挖掘有点仓促。
显然可以使用模板的完全限定名称(在我的示例中是 ::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));
}
不必使用任何技巧让编译器意识到您正在使用 record
作为模板名称而不是引用当前实例化的类型名称。见 [temp.local]/1,强调我的:
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type-specifier of a friend class template declaration, it refers to the class template itself. Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in
<>
.
您发布的解决方法是正确的,但应该不需要;这是编译器中的错误。