[英]How can I use `std::array` for a template parameter of the form `template<typename> class`?
请考虑以下tree
类
template<typename T, template<typename> class Tuple>
class tree
{
private:
T m_value;
Tuple<tree> m_children;
};
template<typename T, std::size_t N>
using static_tree = tree<T, std::array<T, N>>;
这没有明确的定义。 std::array<T, N>
不是Tuple
的合适模板参数。 我假设static_tree
的意图是明确的。 我们可以做点什么
template<std::size_t N>
struct helper
{
template<typename T>
using type = std::array<T, N>;
};
template<typename T, std::size_t N>
using static_tree = tree<T, helper<N>::template type>;
没有helper
类还有其他选择吗?
而不是将辅助函数作为std::array
的例外,我建议将其作为规则。 不使用模板模板参数,而是使用元函数类参数。 当所有地方都是类型(避免模板模板和非类型参数)时,模板元编程会轻松得多:
template<typename T, typename TupleMfn>
class tree
{
private:
using Tuple = TupleMfn::template apply<tree>;
T m_value;
Tuple m_children;
};
有:
template <size_t N>
struct array_builder {
template <class T>
using apply = std::array<T, N>;
};
template <typename T, size_t N>
using static_tree = tree<T, array_builder<N>>;
这样可以更容易地与其他类型的容器一起使用,因为我们可以为模板模板创建一个包装器,为我们提供一个元函数:
template <template <typename...> class X>
struct as_metafunction {
template <class... Args>
using apply = X<Args...>;
};
template <typename T>
using vector_tree = tree<T, as_metafunction<std::vector>>;
如果你感觉特别激动,你可以提供一个元编程友好版本的std::array
:
template <class T, class N>
struct meta_array : std::array<T, N::value> // obviously I am terrible at naming things
{ };
template <size_t N>
using size_t_ = std::integral_constant<size_t, N>;
然后提供tree
占位符args以应用:
template <class T, size_t N>
using static_tree = tree<T, meta_array<_, size_t_<N>>>;
template <class T>
using vector_tree = tree<T, std::vector<_>>;
我认为你的问题包含一个与你明确提出的问题不同的基本问题(它在本回答的前一次迭代中让我失望了)。 结合你问题的不同部分,你实际上是在尝试实例化一些树类,它的成员也是同一个类的std::array
。 这显然是不可能的。 您可能希望树应该包含一些指针 Tuple
(智能或其他)。
一种方法是使用你的助手类,但将类修改为
template<typename T, template<typename> class Tuple>
class tree
{
// Indirection (I'm omitting the question of whether these should be
// smart pointers.
Tuple<tree<T, Tuple> *> m_children;
};
一种不同的方法会使Tuple
成为常规模板参数,如下所示:
#include <array>
#include <type_traits>
template<typename T, class Tuple>
class tree
{
private:
static_assert(
std::is_same<void *, typename Tuple::value_type>::value,
"Tuple must be a container of void *");
private:
T m_value;
Tuple m_children;
};
template<typename T, std::size_t N>
using static_tree = tree<T, std::array<void *, N>>;
int main()
{
static_tree<int, 8> t;
}
一方面,辅助类已被淘汰。 OTOH, Tuple
是void *
的容器:实例化器知道这一点,并且类内部需要执行强制转换。 这是一个权衡。 我会坚持你的原始版本(当然有修改建议)。
除了逻辑上,类X不能包含类X的实际实例的多个副本。
如果我们有
struct X {
std::array<X, 2> data;
};
X
的唯一可能大小是无穷大,因为sizeof(X)
= 2*sizeof(X)
,并且C ++中的所有类型都有sizeof(X)>=1
。
C ++不支持无限大类型。
您的第二个问题是类型实例不是模板。
template<typename T, template<typename> class Tuple>
class tree
这需要一个类型T
和一个template
Tuple
。 第二个参数不是类型 。
template<typename T, std::size_t N>
using static_tree = tree<T, std::array<T, N>>;
在这里,你的第二个参数是一个类型 ,而不是一个模板。
template<std::size_t N>
struct array_of_size {
template<class T>
using result=std::array<T,N>;
};
template<typename T, std::size_t N>
using static_tree = tree<T, array_of_size<N>::template result>;
除了上述“无限大小问题”之外,还能解决你的问题。 这里我们将模板array_of_size<N>::result
传递给tree
。
要解决无限大小问题, 必须在数组中存储指针(或等效的东西)。 所以我们得到:
template<std::size_t N>
struct array_of_ups_of_size {
template<class T>
using result=std::array<std::unique_ptr<T>,N>;
};
template<typename T, std::size_t N>
using static_tree = tree<T, array_of_ups_of_size<N>::template result>;
现在你的static_tree有N
个子节点,每个子节点都是一个类似static_tree
的unique_ptr
。
由于析构函数问题,这仍然不起作用。
template<typename T, template<typename> class Tuple>
class tree
{
private:
T m_value;
Tuple<tree> m_children;
public:
~tree();
};
template<typename T, template<typename> class Tuple>
tree<T,Tuple>::~tree() = default;
我认为以上修复了它,看起来很奇怪。
基本上,当您创建子数组时,树类型不完整。 在销毁时,调用delete。 那时,树必须完整。 通过推迟dtor,我们希望能够处理这个问题。
我不确定模板是否需要这种技术,但它适用于非模板类。
或者您可以按照建议实现模板参数绑定(稍微比您的helper
更通用):
template<std::size_t N, template<typename,std::size_t> class T>
struct bind2nd
{
template<typename F>
using type = T<F,N>;
};
template<std::size_t N, typename T>
using static_tree = tree<T, bind2nd<N,std::array>::template type>;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.