2015-01-14 28 views
20

Her şablon argümanının dahili hesaplamanın ele alabileceği bir değer türü için bulunduğu bir şablon sınıfım var. Şablonlar (işlev aşırı yüklenmesi yerine) gereklidir çünkü değerler boost :: any olarak iletilir ve türleri çalışma zamanından önce net değildir.Variadic template argümanı başına bir sınıf üyesi oluşturma

template<typename ...AcceptedTypes> // e.g. MyClass<T1, T2> 
class MyClass { 
    std::vector<T1> m_argumentsOfType1; 
    std::vector<T2> m_argumentsOfType2; // ... 
}; 

Veya alternatif olarak, ben şablon bağımsız değişken türleri saklamak istediğinizi:

düzgün doğru türlerine döküm için ben, böyle bir şey her variadic argüman türü için üye listesi var istiyorum Bir listede, onunla bazı RTTI büyü yapmak için (?). Ama onları bir std :: initializer_list üyesine nasıl kaydedeceğiniz de belirsizdir.

Yardımlarınız için teşekkürler!

+2

(http://en.cppreference.com/w/cpp/utility/tuple). –

+0

Ayrı üyeler olmalı mı yoksa bir vektörler koleksiyonuna sahip olmak mı? Ör. Vektörlerin bir “std :: array”? [Bunu nasıl çözeceğimi bilmiyorum, ama bu soruya verdiğiniz cevap, bunu nasıl çözeceğimizi bilenlere yardımcı olabilir.] –

+0

Koleksiyon da iyi. Buna yardım edeceğinden emin değilim. Bir noktada konteyner (std :: vektör) sadece türü bilmek gerekiyor. – user1101674

cevap

11

, en iyi yolu bir tuple kullanmaktır. Başka önemli bir şey, onlara bazı adlandırılmış erişim elde etmek olabilir.Ben ne elde etmeye çalıştığınız benzersiz türleri ile birden vektörleri sahip olmaktır tahmin, bu yüzden değeri türüne göre doğru vektörü için "arama" için aşağıdaki özelliği barındırır:

İşte
template <class T1, class T2> 
struct SameType 
{ 
    static const bool value = false; 
}; 

template<class T> 
struct SameType<T, T> 
{ 
    static const bool value = true; 
}; 

template <typename... Types> 
class MyClass 
{ 
    public: 
    typedef std::tuple<vector<Types>...> vtype; 
    vtype vectors; 

    template<int N, typename T> 
    struct VectorOfType: SameType<T, 
     typename std::tuple_element<N, vtype>::type::value_type> 
    { }; 

    template <int N, class T, class Tuple, 
       bool Match = false> // this =false is only for clarity 
    struct MatchingField 
    { 
     static vector<T>& get(Tuple& tp) 
     { 
      // The "non-matching" version 
      return MatchingField<N+1, T, Tuple, 
        VectorOfType<N+1, T>::value>::get(tp); 
     } 
    }; 

    template <int N, class T, class Tuple> 
    struct MatchingField<N, T, Tuple, true> 
    { 
     static vector<T>& get(Tuple& tp) 
     { 
      return std::get<N>(tp); 
     } 
    }; 

    template <typename T> 
    vector<T>& access() 
    { 
     return MatchingField<0, T, vtype, 
       VectorOfType<0, T>::value>::get(vectors); 
    } 
}; 

olduğunu testcase bunu deneyebilirsiniz böylece: Eğer Sınıfım uzmanlaşmak geçirilen türleri listesinde olmayan herhangi bir türü kullanırsanız

int main(int argc, char** argv) 
{ 
    int twelf = 12.5; 
    typedef reference_wrapper<int> rint; 

    MyClass<float, rint> mc; 
    vector<rint>& i = mc.access<rint>(); 

    i.push_back(twelf); 

    mc.access<float>().push_back(10.5); 

    cout << "Test:\n"; 
    cout << "floats: " << mc.access<float>()[0] << endl; 
    cout << "ints: " << mc.access<rint>()[0] << endl; 
    //mc.access<double>(); 

    return 0; 
} 

(çift için bu yorumladı aşımı erişimi bakınız), bir elde edersiniz derleme hatası, çok okunabilir değil, ama gcc en azından sorunun neden olduğu doğru yere işaret ediyor ve en azından böyle bir hata mesajı önerdi Sorunun doğru nedeni - Burada, örneğin, mc.access < çift >() yapmaya çalıştık eğer: Bir [ `std :: tuple`] olarak bağımsız değişken türleri iletebilirsiniz

error: ‘value’ is not a member of ‘MyClass<float, int>::VectorOfType<2, double>’ 
+0

Şimdiye kadar iyi çalışıyor, teşekkürler! Bununla birlikte, bunun yerine > bir vektör istiyorsam ne yapmalıyım? Ben şu hataları alıyorum: hata C2504: 'std :: tuple_element <0, std :: tuple <>>': temel sınıf tanımsız sınıf şablonu örneklerinin oluşturulmasına başvurusuna bakın 'std :: tuple_element <1, std :: tuple >, std :: allocator >>>>> 'derlenerek . .. – user1101674

+0

0 #'nu ve C++ 11 modunu derlediniz mi? Test çantamı biraz değiştirdim, kullanılan "reference_wrapper ", "int" değişkenine basıldı ve her şey normal çalışıyor. Tüm testcase fonksiyonunu koyacağım, böylece onu görebilirsiniz. – Ethouris

+0

Çok teşekkürler, işe yarıyor! Derleyici hatalarını tetikleyen şey, Richard Hodges tarafından yukarıda açıklandığı gibi, kodun bir türünü otomatik olarak eklemeye çalıştı. – user1101674

4

πάντα-ῥεῖ'nın yorumunda belirtildiği gibi böyle bir şey yapmanın bir yolu bir tuple kullanmaktır. Açıklamamış olması (muhtemelen sizi kendinizden kurtarmak), bunun nasıl göründüğü. İşte

bir örnek:

using namespace std; 

// define the abomination  
template<typename...Types> 
struct thing 
{ 
    thing(std::vector<Types>... args) 
    : _x { std::move(args)... } 
    {} 

    void print() 
    { 
     do_print_vectors(std::index_sequence_for<Types...>()); 
    } 

private: 
    template<std::size_t... Is> 
    void do_print_vectors(std::index_sequence<Is...>) 
    { 
     using swallow = int[]; 
     (void)swallow{0, (print_one(std::get<Is>(_x)), 0)...}; 
    } 

    template<class Vector> 
    void print_one(const Vector& v) 
    { 
     copy(begin(v), end(v), ostream_iterator<typename Vector::value_type>(cout, ",")); 
     cout << endl; 
    } 

private: 
    tuple<std::vector<Types>...> _x; 
}; 


// test it 
BOOST_AUTO_TEST_CASE(play_tuples) 
{ 
    thing<int, double, string> t { 
     { 1, 2, 3, }, 
     { 1.1, 2.2, 3.3 }, 
     { "one"s, "two"s, "three"s } 
    }; 

    t.print(); 
} 

beklenen çıkışı:

template<typename ... Ts> 
using variant_vector = boost::variant< std::vector<Ts>... >; 

template<typename ...Ts> 
struct MyClass { 
    using var_vec = variant_vector<Ts...>; 
    std::array<var_vec, sizeof...(Ts)> vecs; 
}; 

bir varyant-vektör oluşturun: Burada

1,2,3, 
1.1,2.2,3.3, 
one,two,three, 
+0

ah, vektör argümanlarını alan ekstra yapıcıyı özledim. Std :: tuple > 'nin başlatıcı listeleri ile uğraşıyordum ve bu kurucuların açık doğasına rastlıyordum. – TemplateRex

+0

Bu eğlenceli bir alıştırmadır ama eğer üretim kodumuzu gördüğümde, birisinin ateş etmesini istiyorum :-) –

+1

bu tür bir egzersizin faydaları olabilir, ör. Veri yönelimli tasarımda genellikle std :: tuple 'yerine std :: vector ' yerine daha iyi önbellekleme vb. 'i ararız. eski. Böyle bir dönüşümü el ile kodlamaktan kaçınmak istiyorsanız, bazı değişken tuple büyüleri işe yarayabilir! – TemplateRex

0

boost::variant kullanarak daha az mükemmel verimli uygulamasıdır Bu, içinde türlerin bir listesini tutabilir. İçeriği almak için boost::variant'u kullanmanız gerekir (bu da içeriğin türünü bilmek veya ziyaretçi yazmak anlamına gelir).

Daha sonra, bu varyant vektörlerinin bir dizisini, her biri için bir adet olmak üzere depolarız.

Artık, sınıfınız yalnızca bir tür veri taşıyorsa, diziyle birlikte kapatabilir ve yalnızca var_vec türünde bir üyeye sahip olabilirsiniz.

Neden her türden bir vektör isteyeceğinizi göremiyorum. Her elemanın herhangi bir tipte olduğu bir vektör istemek görebiliyordum. Yukarıdaki variant<vector<Ts>...>'un aksine, vector<variant<Ts...>> olacaktır.

variant<Ts...>, birleşim ile birlikte boost olduğunu. any, boost smart-void*'dur. optional, boost burada veya değil.

template<class...Ts> 
boost::optional<boost::variant<Ts...>> to_variant(boost::any); 

bir any alır ve variant içinde Ts... türlerinden herhangi dönüştürmek çalışır ve döner o eğer başarılı olursa (ve boş optional değilse döner) yararlı bir fonksiyonu olabilir.

template<typename ...AcceptedTypes> // e.g. MyClass<T1, T2> 
class MyClass { 
    std:tuple<std::vector<AcceptedTypes>...> vectors; 
}; 

Bu sihirli saha isimlerini büyü yapamaz çünkü "alanları" çarpmak için tek yol: Zaten ima edilmiş gibi

İlgili konular