5

请考虑以下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没有课程还有其他选择吗?

4

4 回答 4

6

与其让辅助函数成为 的例外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

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<_>>;
于 2016-03-19T23:36:08.207 回答
1

我认为您的问题包含一个与您明确提出的问题不同的基本问题(它在此答案的前一次迭代中让我有点失望)。结合问题的不同部分,您实际上是在尝试实例化一些树类,该树类的成员也属于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 *:实例化器知道这一点,并且类内部需要执行强制转换。这是一个权衡。我会坚持使用您的原始版本(当然,建议进行修改)。

于 2016-03-19T22:52:41.863 回答
0

类 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

这需要一个 typeT和一个template Tuple. 第二个参数不是 type

template<typename T, std::size_t N>
using static_tree = tree<T, std::array<T, N>>;

在这里,您的第二个参数是 type,而不是模板。

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>::resulttree.

要解决无限大小的问题,您必须在数组中存储指针(或等效的东西)。所以我们得到:

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孩子,每个孩子都是unique_ptr一个相似的static_tree.

由于析构函数问题,这仍然不起作用。

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;

我认为以上解决了它,尽管看起来很奇怪。

基本上,当您制作子数组时,树类型是不完整的。在销毁时,调用删除。此时,树必须是完整的。通过推迟 dtor,我们有望解决这个问题。

我不确定模板是否需要这种技术,但它适用于非模板类。

于 2016-03-20T01:56:49.860 回答
0

或者您可以按照您的建议实现模板参数绑定(比您的更通用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>;
于 2016-03-20T03:08:19.287 回答