簡體   English   中英

如何使用`std :: array`作為`template模板的模板參數 <typename> class`?

[英]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, Tuplevoid *的容器:實例化器知道這一點,並且類內部需要執行強制轉換。 這是一個權衡。 我會堅持你的原始版本(當然有修改建議)。

除了邏輯上,類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_treeunique_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM