如何使用`std :: array`作为`template <typename> class`形式的模板参数?

时间:2016-03-19 22:33:11

标签: c++ templates c++14 template-templates

请考虑以下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 个答案:

答案 0 :(得分: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<_>>;

答案 1 :(得分:1)

我认为你的问题包含一个与你明确提出的问题不同的基本问题(它在这个答案的前一次迭代中让我失望了)。结合问题的不同部分,您实际上试图实例化一个具有同一类std::array成员的树类。这显然是不可能的。您可能希望树应该包含一些指针的<{1}} (智能或其他)。

这样做的一种方法是使用你的助手类,但将类修改为

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

一方面,帮助类已被淘汰。 OTOH,#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; } Tuple的容器:实例化器知道这一点,并且类内部需要执行强制转换。这是一种权衡。我会坚持你的原始版本(当然建议修改)。

答案 2 :(得分:0)

除了逻辑上,类X不能包含类X的实际实例的多个副本。

如果我们有

public Employee(int id, String name, int salary, int age, Date dateOfJoining){
    this.id = id;
    this.name = Objects.requireNonNull(name);
    if (salary <= 0) {
        throw new IllegalArgumentException(
            "The salary should be positive, but is "+salary);
    }
    this.salary = salary;
    if (age <= 0) {
        throw new IllegalArgumentException(
            "The age should be positive, but is "+salary);
    }
    this.age = age;
    this.dateOfJoining = Objects.requireNonNull(dateOfJoining);
}

struct X { std::array<X, 2> data; }; 唯一可能的大小是无穷大,X = sizeof(X),而C ++中的所有类型都有2*sizeof(X)

C ++不支持无限大类型。

你的第二个问题是类型实例不是模板。

sizeof(X)>=1

这需要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>>;

除了以上&#34;无限大小问题&#34;之外,解决您的问题。在这里,我们将模板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

现在您的static_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>; 个孩子,每个孩子都是N到类似的unique_ptr

由于析构函数问题,这仍然无效。

static_tree

我认为以上修复了它,看起来很奇怪。

基本上,当您创建子数组时,树类型不完整。在销毁时,调用delete。那时,树必须完整。通过推迟dtor,我们希望能够处理这个问题。

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

答案 3 :(得分: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>;