请考虑以下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
类还有其他选项吗?
答案 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>;