2010-09-06 37 views
5

Variadic şablonlarını kullanarak her argümanı tuple'dan nasıl okuyabileceğimi biraz kafam karıştı. Ben gibi ana dosyadan diyoruzvariadic şablondan bağımsız değişkenleri oku

template<class...A> int func(A...args){ 
int size = sizeof...(A); 
.... } 

:

bu işlevi düşünün Şimdi

func(1,10,100,1000); 

, ben muktedir func vücut uzatmak zorunda bilmiyorum Her argümanı ayrı ayrı okumak için, örneğin argümanları bir dizide saklayabilirim.

+3

Önceki sorunuzda neyi özlediniz? (http://stackoverflow.com/questions/3634379/variadic-templates) Ve neden sorularınızın cevaplarını kabul etmiyorsunuz? – ereOn

+0

http://stackoverflow.com/questions/3634379/variadic-templates/3645307#3645307 – kennytm

+1

Yanıt, bağlantılı konuya (Motti, no upvotes?) Olmalıdır. – visitor

cevap

11

İlk N (genellikle bir) bağımsız değişkeni tüketen işlevler için geçersiz kılmaları sağlamanız gerekir.

void foo() { 
    // end condition argument pack is empty 
} 

template <class First, class... Rest> 
void foo(First first, Rest... rest) { 
    // Do something with first 
    cout << first << endl; 

    foo(rest...); // Unpack the arguments for further treatment 
} 

Variadic parametresini paketinden çıkardığınızda, bir sonraki aşırı yükü bulur.

Örnek: Rest o foo() çağırır açma bu durumda hiçbir üye içerene kadar (böyle devam

foo(true, Rest = { 'a', "hello"}); // First = bool 

Ve:

foo(42, true, 'a', "hello"); 
// Calls foo with First = int, and Rest = { bool, char, char* } 
// foo(42, Rest = {true, 'a', "hello"}); // not the real syntax 

Ardından sonraki düzeyinden önceki Rest genişletmek ve almak argüman olmadan aşırı yük). farklı

tamamını argüman bir std::tuple

template <class... Pack> 
void store_pack(Pack... p) { 
    std::tuple<Pack...> store(p...); 
    // do something with store 
} 

kullanabilirsiniz paketi saklamak istiyorsanız eğer paketini saklama


Ancak bu daha az yararlı görünmektedir.

paketinde tüm değerler böyle saklayabilir aynı tip ise o

homojen olmadığını paketini saklama:

vector<int> reverse(int i) { 
    vector<int> ret; 
    ret.push_back(i); 
    return ret; 
} 

template <class... R> 
vector<int> reverse(int i, R... r) { 
    vector<int> ret = reverse(r...); 
    ret.push_back(i); 
    return ret; 
} 

int main() { 
    auto v = reverse(1, 2, 3, 4); 
    for_each(v.cbegin(), v.cend(), 
     [](int i) { 
      std::cout << i << std::endl; 
     } 
    ); 
} 

Ancak bu da az kullanışlı görünüyor. Eğer dizide argümanları saklamak gerekiyorsa aşağıdaki gibi

+0

@Motti: Ne demek istediğini anladım. Ama hala iki sorum var: 1- eğer veri tipini belirtmek istersem, foo işlevini şu şekilde çağırabilir miyim: foo (42, true, 'a', "merhaba") 2- Paketleri açtıktan sonra saklamak istediğim yeri saklamak için değerleri okuyabildiğim ve bu benim asıl sorumuydu! – sami

+0

@sami, 1. Standardın ne dediğini bilmiyorum ama g ++ (42) foo'yu kabul ediyor. Bu durumda '' '' '' '' '' '' '' '' '' '' 'yerine' '' '' 'yerine' '' '' '' '' '' '' '' '' 'arg'ünü zorlar. – Motti

+0

@sami, 2. Eğer bunlar farklı tipte ise, bunları düzenli bir dizide saklayamazsınız (“boost :: any” ya da Kirill'in önerdiği gibi bir şey kullanmadığınız sürece) – Motti

1

Eğer boost::any dizisi kullanabilirsiniz:

template<typename... A> int func(const A&... args) 
{ 
    boost::any arr[sizeof...(A)] = { args... }; 
    return 0; 
} 
3

argümanlar aynı türdeki tüm iseniz, (böyle bir dizideki argümanları depolayabilir türleri farklı ise, sana boost::any kullanabilirsiniz varsayalım ama sonra size verilen şablonun dışına öğrenmek için gidiyoruz nasıl görmüyorum

template <class T, class ...Args> 
void foo(const T& first, const Args&... args) 
{ 
    T arr[sizeof...(args) + 1] = { first, args...}; 
} 

int main() 
{ 
    foo(1); 
    foo(1, 10, 100, 1000); 
} 

: dizinin ilk argüman türü) kullanılarak hangi öğe hangisidir (nasıl gidiyorsunuz saklanan değerleri kullanmak için).


Düzenleme: argümanlar aynı türdeki tüm vardır ve bir STL kabın içine saklamak istiyorsanız , yerine std::initializer_list<T> kullanabilirsiniz. Örneğin, tersten değerlerini saklama Motti en örnek: argümanlar farklı türde varsa bir diziye yapışmasını için

#include <vector> 
#include <iostream> 
#include <iterator> 

template <class Iter> 
std::reverse_iterator<Iter> make_reverse_iterator(Iter it) 
{ 
    return std::reverse_iterator<Iter>(it); 
} 

template <class T> 
std::vector<T> reverse(std::initializer_list<T> const & init) 
{ 

    return std::vector<T>(make_reverse_iterator(init.end()), make_reverse_iterator(init.begin())); 
} 

int main() { 
    auto v = reverse({1, 2, 3, 4}); 
    for (auto it = v.begin(); it != v.end(); ++it) { 
     std::cout << *it << std::endl; 
    } 
} 
+0

, destek kütüphanesi de değişken şablonlar için STL konteynerlerini destekliyor mu? – sami

+0

Bağımsız değişkenler aynı veri türünden değilse ne hakkında? – sami

+0

Farklı türlerde değerler için standart bir "kapsayıcı", "std :: tuple" dır. – UncleBens

1

, ayrıca örneğin Yani std::common_type<>

template<class ...A> void func(A ...args){ 
    typedef typename common_type<A...>::type common; 
    std::array<common, sizeof...(A)> a = {{ args... }}; 
} 

, func(std::string("Hello"), "folks") bir dizi oluşturur kullanabilirsiniz std::string.

İlgili konular