2016-03-19 15 views
5

aşağıdaki tree sınıf iyi tanımlanmış değildir"Şablon <typename> sınıfının" şablon parametresi için "std :: array" işlevini nasıl kullanabilirim?

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>>; 

düşünün. Tuple için std::array<T, N> uygun bir şablon parametresi değildir. static_tree'un amacının açık olduğunu farz ediyorum. Biz helper sınıfa olmadan başka seçenek var mı

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>; 

gibi bir şey yapabilir?

+0

sahibi 'tree', neden Tuple' bir tür parametresi yerine bir şablon' yapmaz parametre? –

+0

@AlanStokes Bu durumda static_tree'yi nasıl tanımlarım? Bu sonsuz bir keşif olurdu, değil mi? – 0xbadf00d

+0

Gerçek şu ki, std :: array' bir tamsayı parametresine ihtiyaç duyar. Bunu belirtmenin bir yolu yok * bir yerlerde *. Bunun olduğu yerde birçok alternatif var ve seninki açıktan çok uzak değil. – davidhigh

cevap

1

Sorunun açık bir şekilde sorduğundan farklı bir temel sorun olduğunu düşünüyorum (bu cevabın önceki yinelemesinde beni biraz attı). Sorunuzun farklı bölümlerini birleştirdiğinizde, aynı sınıfın bir std::array üyesi olan bir ağacın sınıfını temel olarak oluşturmaya çalışıyorsunuz. Bu açıkça imkansız. Muhtemelen ağacın Tupleişaretçisini (akıllı veya başka bir şekilde) tutmasını isteyebilirsiniz. aşağıdaki gibi yapmak

bir yolu, böylece yardımcı sınıf kullanmak olabilir, ancak farklı bir yolu Tuple düzenli şablon parametresi yapacak

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; 
}; 

için sınıf değiştirme olacaktır:

#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; 
} 

Bir yandan, yardımcı sınıf elendi. OTOH, Tuple, void * numaralı bir kapsayıcıdır: buradaki ileticilerin bunun farkındadır ve sınıfın dahili olarak cast gerçekleştirmesi gerekir. Bu bir tradeoff. Orijinal versiyonunuza sadık kalacağım (tabii ki önerilen modifikasyonlarla).

+1

Tanımı ile 'static_tree' bir ağaç değil * olduğunu biliyorsunuz, değil mi? Bir ağacın çocukları da ağaç olmalı. – 0xbadf00d

+0

@ 0xbadf00d Haklısınız, ancak yansıma üzerine, bu sorunun bir sorundan kaynaklandığını düşünüyorum. Güncellemeye bakın. –

4

Yardımcı işlev yerine, std::array için bir istisna olmak yerine, kural olmasını öneriyorum. Bir şablon şablonu parametresi almak yerine, metafunction sınıf parametresini alın.

template<typename T, typename TupleMfn> 
class tree 
{ 
private: 
    using Tuple = TupleMfn::template apply<tree>; 

    T m_value; 
    Tuple m_children; 
}; 

ile: Bu başka türlü kullanmak kolaylaştıracaktır

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>>; 

her yerde her şeyin bir türü (kaçınarak şablon şablonlar ve non-tipi argümanlar) olduğunda Şablon metaprogramming çok daha kolay

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>>; 

: biz geri üst-işlevin bize verdiği şablon şablonlar için bir sarıcı yapabilir çünkü hem kaplar,

özellikle alıngan duygu ediyorsanız, std::array bir metaprogramming dostu sürümünü sağlayabilir:

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>; 

Sonra uygulamak tree için yer tutucu args sağlar:

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<_>>; 
+0

"Ağaçınız" * bir ağaç değildir, çünkü "m_children" T 'nin bir tupudur. – 0xbadf00d

+0

@ 0xbadf00d Yazım hatası – Barry

0

A sınıfı X içeremez mantıksal olarak hariç, X sınıfının gerçek örneklerinin birden çok kopyası.

bir biz

struct X { 
    std::array<X, 2> data; 
}; 

X için mümkündür boyutu sonsuz varsa sizeof(X) = 2*sizeof(X) ve sizeof(X)>=1 sahip C++ tüm türleri.

C++, sonsuz büyüklükteki türleri desteklemez.

İkinci probleminiz, tip örneklerinin şablon olmamasıdır.

template<typename T, template<typename> class Tuple> 
class tree 

bu tip T ve templateTuple sürer. İkinci argüman , tipinde değildir.

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

burada, ikinci argüman tip değil, bir şablondur.

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>; 

, yukarıdaki "sonsuz büyüklük sorunu" dışında, sorunu çözmek olacaktır. Burada array_of_size<N>::result şablonunu tree'a geçiriyoruz.

Sonsuz boyut problemini çözmek için, dizisinde mağaza işaretleyicileri (veya eşdeğer bir şey) gerekir.

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>; 

ve şimdi static_tree benzer static_tree bir unique_ptr her biri N çocuğu vardır: Yani biz olsun.

Bu hala çalışmıyor, çünkü yıkıcı sorunları nedeniyle.

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; 

Ben görünse de yukarıdaki düzeltmeleri tuhaf, düşünüyorum.

Temel olarak, alt dizi yaptığınızda, ağaç türü eksik. Imhada, silme denir. Bu noktada ağaç tamamlanmış olmalı. Dergiyi erteleyerek, umarım sorunla ilgileniriz.

Bu teknik şablonlar için gerekli olup olmadığı belirsiz, ancak şablon olmayan sınıflar içindir.

0

Yoksa önerildiği gibi bir şablon parametresi bağlama uygulamak (biraz daha genel senin 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>; 
İlgili konular